Gcc fails: "overload call is ambiguous", while clang doesn't
I have the following code:
#include <experimental/string_view> struct b_symbol { template <typename T> explicit b_symbol(T&& symbol) : symbol(std::forward<T>(symbol)) { } std::experimental::string_view symbol; }; struct b_utf8 { template <typename T> explicit b_utf8(T&& value) : value(std::forward<T>(value)) { } std::experimental::string_view value; }; struct value { explicit value(b_utf8) {} explicit value(b_symbol) {} }; int main() { value v({b_utf8("test")}); } You can try it on godbolt .
If I compile it with clang (3.8.0):clang++ oload.cpp -std=c++1y
everything is working fine.
If I compile it with gcc (6.1.1 20160602)g++ oload.cpp -std=c++1y
I get:
oload.cpp: In function 'int main()': oload.cpp:30:29: error: call of overloaded 'value(<brace-enclosed initializer list>)' is ambiguous value v({b_utf8("test")}); ^ oload.cpp:25:14: note: candidate: value::value(b_symbol) explicit value(b_symbol) {} ^~~~~ oload.cpp:24:14: note: candidate: value::value(b_utf8) explicit value(b_utf8) {} ^~~~~ oload.cpp:23:8: note: candidate: constexpr value::value(const value&) struct value { ^~~~~ oload.cpp:23:8: note: candidate: constexpr value::value(value&&) Why is this a difference?
Is gcc behavior right?
EDIT: As Slavanap noted in his answer, the error can be circumvented by removing curly braces on the call site. However, I would like to know why compilers behave differently.
You pass an initialization list to a constructor that explicitly accepts either b_utf8 or b_symbol, and is not correct.
You must define a constructor that takes an initialization list if you do not want to use implicit casts.
I think this happens during the change process for C ++ 17, and you will be allowed to do this as clang.
EDIT: Interesting
struct b_utf8 { b_utf8() = default; //b_utf8(){} }; struct value { explicit value(b_utf8) {} }; int main() { value v({b_utf8()}); } compiles but
struct b_utf8 { //b_utf8() = default; b_utf8(){} }; struct value { explicit value(b_utf8) {} }; int main() { value v({b_utf8()}); } cannot overload. I am not sure why, as far as I can tell, the permission of an overload should behave the same in these two cases.