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
.
From [class.conv.fct]/2:
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.This seems to be a Clang bug. [over.match.list]/1:
Since the second line compiles fine, there is an inconsistency: They should be equivalent when it comes to overload resolution.
clang doesn't seem to care whether the conversion operator is
explicit
or not, and I believe it is correct due to the wording in [over.best.ics].First of all, the direct-initialization
works on both gcc and clang, and is explained by [class.conv.fct]/2 as mentioned in KerrekSB's answer.
The direct-list-initialization
on the other hand, does not consider any user defined conversions,
explicit
or not.Quoting N3337, §13.3.3.1/4 [over.best.ics]