I'm getting a compiler error about a type conversion that should be legal, to my eyes.
Let's say I have a home-grown string class, convertible from and to char*:
class custom_string { public: custom_string(const char* str) : _str{str} {} operator const char*() const { return _str; } private: const char* _str; }; Out in the wild, I want to use this custom class interchangeably with std::string in a number of ways:
struct pod_t { std::string str; int other_data; }; void test() { custom_string cstr("Hello"); std::set<std::string> strings; strings.emplace(cstr); pod_t pod {cstr, 42}; // C2440: 'initializing': cannot convert from 'custom_string' to 'std::string' } I'm using MSVC with the /std:c++20 flag.
Why does the last line result in a compiler error? If the compiler can figure out the path from custom_string to std::string in the case of the emplace function (presumably it's using the char* operator), why can't it do the same when I'm trying to initialize the struct?
custom_stringtochar *, and another fromchar *tostd::string. You need to add anoperator std::stringto your custom string, which pretty much defeats the purpose.std::stringcan be constructed from acustom_string, i.e. this compiles:std::string test(cstr);The fact that it can be directly constructed is not enough to "assist" the compiler in thepod_tcase?std::string test(cstr);is one conversion.pod_t pod {cstr, 42};is two conversions. You can dopod_t pod {std::string{cstr}, 42};to do one conversion.std::string test(cstr)is not a conversion. It is direct-initialization which does overload resolution against constructors ofstd::stringand selects one. The implicit conversion sequence is then in the argument of the selected constructor. In this conversion sequence there can also only be one user-defined conversion (i.e. construct/conversion function call).emplacecall can also use direct-initialization, because of the perfect forwarding of the argument types? And direct-initialization takes advantage of constructor overloading on the "target", while implicit conversion can only take advantage of user-defined conversion operators on the source? @user17732522 do I have that right?