Visual Studio fails to instantiate cast (conversion) operator template (T=bool) in the context of boolean operations
c++, c++11, visual-c++, visual-studio-2010, visual-studio-2012
Solution
It's a bug, at least in C++03 (not sure about C++11).
According to the overload resolution rules in C++03 §13.3.1.2, the built-in `||` operator is selected, since no user-defined `||` operator is defined for `S`.
§5.15/1 says:
The `||` operator groups left-to-right. The operands are both implicitly converted to `bool` (clause 4). [...]
§12.3/2 says:
User-defined conversions are applied only where they are unambiguous (10.2, 12.3.2). [...]
§12.3/5:
User-defined conversions are used implicitly only if they are unambiguous. [...] Function overload resolution (13.3.3) selects the best conversion function to perform the conversion.
§13.3.2/3:
Second, for `F` to be a viable function, there shall exist for each argument an implicit conversion sequence (13.3.3.1) that converts that argument to the corresponding parameter of `F`.
Clearly `S` defines a user-defined conversion to `bool`. The built-in `||` operator is a viable function for the overload resolution, and since it's the only one, it's the best. So the expression is well-formed.
Also of note is §4/3, which says:
An expression `e` can be implicitly converted to a type `T` if and only if the declaration “`T t=e;`” is well- formed, for some invented temporary variable `t` (8.5). [...]
So I'm curious whether Visual Studio also produces an error for the statement `bool b = S();`.
Problem
Why do Visual Studio 2010 and Visual Studio 2012 fail to compile this code? Codepad.org, Xcode, gcc, LLVM, Clang all have no problem but Visual Studio poops the bed: ``` struct S { template <class T> inline operator T () const { return T (); } }; int main () { // NOTE: "S()" denotes construction in these examples struct F { void operator() (bool) { } static void toint (int) { } static void tostr (char const*) { } }; bool b1 = S (); // Okay bool b2 (S ()); // Okay F () (S ()); // Okay F::toint (S ());// Okay F::tostr (S ());// Okay S () || false; // Error: error C2676: binary '||' : 'vf::S' does // not define this operator or a conversion to a type // acceptable to the predefined operator return 0; } ``` Adding the `explicit` keyword doesn't change a thing for gcc or clang. The error message produced is: ``` error C2676: binary '||' : 'S' does not define this operator or a conversion to a type acceptable to the predefined operator ```