The following code compiles under Clang/GCC under the C++17 standard, but does not compile under MSVC with -std:C++17 /Zc:ternary.
struct CStringPtr
{
const char *m_pString = nullptr;
CStringPtr() = default;
CStringPtr( const char *pString ) : m_pString( pString ) { }
operator const char *() const { return m_pString; }
};
int main( int argc, char ** )
{
bool b = !!argc;
const char *X = b ? CStringPtr( "inside" ) : "naked";
const char *Y = b ? "naked" : CStringPtr( "inside" );
CStringPtr Z = b ? CStringPtr( "inside" ) : "naked";
CStringPtr W = b ? "naked" : CStringPtr( "inside" );
// Silence unused-variable warnings.
return X && Y && Z && W;
}
Link to godbolt's compiler explorer with all three: https://godbolt.org/z/6d5Mrjnd7
MSVC emits an error for each of those four lines:
<source>(19): error C2445: result type of conditional expression is ambiguous: types 'const char [6]' and 'CStringPtr' can be converted to multiple common types
<source>(19): note: could be 'const char *'
<source>(19): note: or 'CStringPtr'
Whereas Clang/GCC each call the CStringPtr constructor for the naked string for all four of those cases.
In the MSVC /Zc:ternary documentation they claim that the flag enables standards-compliant resolution of the ternary operator, which implies that either there's a bug in MSVC's implementation or Clang/GCC are not standards-compliant here.
The one other note here is that the MSVC docs mention an exception in this exact case with respect to the const char * type being used:
An important exception to this common pattern is when the type of the operands is one of the null-terminated string types, such as const char*, const char16_t*, and so on. You can also reproduce the effect with array types and the pointer types they decay to. The behavior when the actual second or third operand to ?: is a string literal of corresponding type depends on the language standard used. C++17 has changed semantics for this case from C++14.
So, is MSVC non-compliant under C++17 rules? Or are Clang/GCC?