The following code compiles with GCC 4.9.2 but not with Clang 3.5.0:
#include <string>
class Foo
{
public:
explicit operator std::string() const;
};
std::string bar{Foo{}}; // Works in g++, fails in clang++
std::string baz(Foo{}); // Works in both
clang++ says:
foo.cpp:9:13: error: no matching constructor for initialization of 'std::string'
(aka 'basic_string<char>')
std::string bar{Foo{}};
^ ~~~~~~~
...: note: candidate constructor not viable: no known conversion from 'Foo' to
'const std::basic_string<char> &' for 1st argument
basic_string(const basic_string& __str);
^
Curiously, it works if std::string is replaced with a primitive type like int.
This seems to be a Clang bug. [over.match.list]/1:
When objects of non-aggregate class type
Tare list-initialized (8.5.4), overload resolution selects the constructor in two phases:
- [..]
- If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class
Tand the argument list consists of the elements of the initializer list.
Since the second line compiles fine, there is an inconsistency: They should be equivalent when it comes to overload resolution.
From [class.conv.fct]/2:
A conversion function may be explicit (7.1.2), in which case it is only considered as a user-defined conversion for direct-initialization (8.5).
So the question is how you initialize your objects. Clearly baz is direct-initialized, so this works. By contrast, bar is direct-list-initialized, but not direct-initialized, and so the explicit conversion is not available.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With