Reputation: 1814
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 runs 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 that difference?
Is the behavior of gcc correct?
EDIT: As slavanap pointed out in his answer, the error can be circumvented by removing the curly braces on call-site. Non the less I would like to know why the compilers behave differently.
Upvotes: 5
Views: 159
Reputation: 880
You are passing an initialiser list to a constructor that explicitly takes either a b_utf8 or a b_symbol, neither is correct.
You must define a constructor that takes an initialiser list if you don't want to use implicit casts.
I think this is in the process of being changed for C++17 and you will be allowed to do it the clang way then.
EDIT: Interestingly
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()});
}
fails overload resolution. I'm not sure why, as far as I can tell overload resolution should behave the same in those two cases.
Upvotes: 1
Reputation: 907
In the error it says <brace-enclosed initializer list>
.
// Why not just try to call
value v(b_utf8("test"));
// instead
value v({b_utf8("test")});
// ?
Upvotes: 0