Custom conversion and cast to link function

I encounter a compilation error for the following code:

class SymbolGroup { std::string d_; public: SymbolGroup(std::string a):d_(a){} // explicit operator const std::string&() const { return d_;} // compiles explicit operator std::string() const { return d_;} // Does not compile }; inline bool operator==(const SymbolGroup& lhs, const SymbolGroup& rhs) { return static_cast<const std::string&>(lhs) == static_cast<const std::string&>(rhs); } int main(){ SymbolGroup a("hello"); SymbolGroup b("hello"); if (a==b) std::cout << "they are the same\n"; return 0; } 

Without 'const' and '&' in the user type conversion string, it does not compile in g ++ (4.8) with -std = C ++ 11 flag:

error: incorrect initialization of a link like std :: string & {aka std :: basic_string &} from an expression like 'const string {aka const std :: basic_string} explicit operator std :: string & () const {return d _;}

The code compiles on Clang in both directions. Which compiler is right? Should this code be compiled using operator std::string() ?

+6
source share
2 answers

UPDATE My previous answer was completely wrong. I apologize! TL; DR; clang is correct to accept the code, gcc is wrong to reject it.


Firstly, from [expr.static.cast]:

The expression e can be explicitly converted to type T using static_cast of the form static_cast<T>(e) if the declaration is T t(e) ; well formed, for some invented time variable t (8.5).

Thus, we try to directly initialize an object of type std::string const& explicitly from an object of type SymbolGroup const& . There is a section on link initialization with the conversion function: “Initialization with the conversion function for direct link binding” [over.match.ref]:

Under the conditions specified in 8.5.3, a link can be bound directly to a glvalue or class value, which is equal to the result of applying the transform function to the initializer expression. Overload resolution is used to select the conversion function to call. Assuming that “cv1 T” is the base type of the link being initialized, and “cv S” is the type of the initializer expression, with S the type of the class, candidate functions are selected as follows:

- The transformation functions of S and its base classes are considered. Those implicit function conversions that are [...] candidate functions. For direct initialization, these are explicit conversion functions that are not hidden inside S and return the type "lvalue reference to cv2 T2" or "cv2" T2 "or" rvalue reference to cv2 T2 "respectively, where T2 is the same type as T or can be converted to type T with qualification conversion (4.4), are also candidate functions.

The first part does not apply, since our conversion function is explicit , so I skipped it. The second part of. We have cv1 T const std::string , so our conversion function to std::string is a candidate function, since std::string can be converted to const std::string with qualification conversion.


gcc is wrong here, and I filed error 66893 , confirmed by our own expert in C ++ and everyone around the good guy Jonathan Wackel , as well as Clang chief developer and standard C ++ editor Richard Smith (after I completely embarrassed myself with the submission Clang errors).

+4
source

Ok sir, the answer is pretty simple. Instead of referring to a constant as a reference:

 return static_cast<const std::string&>(lhs) == static_cast<const std::string&>(rhs); 

Set your type to std::string :

 return static_cast<std::string>(lhs) == static_cast<std::string>(rhs); 

And enjoy the working code :)

+1
source

All Articles