After an error in my own code, where (in my opinion) the wrong overload was chosen by the compiler, I searched for an explanation, but could not find a simple one. I found Herb Sutter GOTW 49 , which is dedicated to the issue of specialization. I also found some questions about stackoverflow, but none of them could explain the reason for me, nor provide me with good solutions.
I have one Foo class that can be built from a boolean. I found out (the hard way) that std :: string can also be built from bool (false).
I have three (boilerplate) methods with different arguments, as shown below. One method accepts "any" template argument and two specializations that take a Foo structure, and the other takes a string.
#include <string> #include <iostream> struct Foo { Foo() : value( false ){ }; Foo( bool v ) : value ( v ) { } Foo( const bool& v ) : value( v ) { } bool value; }; template< typename T > void bar( const T& value ) { std::cerr << "template bar" << std::endl; } template< > void bar< Foo >( const Foo& ) { std::cerr << "template bar with Foo" << std::endl; } template< typename T > void bar( const std::string& ) { std::cerr << "template bar with string" << std::endl; } int main( int argc, char* argv[] ) { bar( false ); // Succeeds and calls 1st bar( const T& ) bar< Foo >( false ); // Crashes, because 2nd bar( const std::string& ) // is called with false promoted to null pointer. return 0; }
I tested this with Visual Studio 2010 and with MinGW (gcc 4.7.0). GCC gives warning compilation fine, but msvc does not:
main.cpp:34:20: warning: converting 'false' to pointer type for argument 1 of 'std::basic_string< ... ' [-Wconversion-null]
Minor update (in code): Even explicit specialization does not work with Foo. \
Small update 2: the compiler does not complain about "ambiguous overload".
Minor update 3: Some people say that two Foo constructors that accept a bool will “invalidate” Foo. I tested similar versions with only one conversion constructor. They also do not work.
Questions:
- Why is the compiler trying to call a version of a string argument?
- And why adding the
<Foo> addon to the bar () line matters. - How can I prevent this. For instance. can I get the compiler to select
bar( const Foo& ) when entering bool? - Alternatively, is it possible to force compilation when calling
bar< Foo >( false ) ?
André source share