Strange C ++ Template Template Specialization Problem

I ran into the strange problem of method specialization.

Given this code ...

#include <string> class X { public: template< typename T > void set( T v ); }; template<> void X::set( const std::string & v ) { } template<> void X::set( int v ) { } int main( int, char *[] ) { X x; std::string y; x.set( y ); x.set( 1 ); } 

When I associate it with g ++ 4.3.3, I get an undefined link to void X::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) .

Basically this is an undefined reference to void X::set( std::string ) .

So my question is: why doesn't the compiler use specialization with const std::string & ?

If I explicitly call x.set< const std::string & >( y ) , then this compiles and the links are fine.

+4
source share
4 answers

Perhaps this article will explain the situation.
You can expect specialization void X::set( const std::string& ) will participate in overload resolution. However, surprisingly, specializations are not involved in overload resolution.
In the call to x.set( y ) compiler infers the type T into the primary template from the argument y with the type std::string . Thus, the compiler outputs that T is std::string , then the search matches the specialization. However, since std::string and const std::string& are different types, the compiler selects the main template at the end.

After choosing the right primary template, the corresponding specialization is selected in the same way as for the class template. The reason the specialization set( const std::string& ) not selected is similar to the fact that the specialization A< std::string > not selected in the following code:

 template< class > class A; // primary template<> class A< const std::string& > {}; // specialization int main() { A< std::string > a; // This doesn't select the specialization } 
+2
source

Returning to the original sentence after compilation:

Your method signature for the string should not be a reference. Must be:

 template<> void X::set( const std::string v ) { } 

This is because in the template definition you specified T paramater , not T& paramater

+3
source

This is a completely wrong syntax. When you specialize in patterns, you must include angle brackets with the types for which you specialize. For instance:.

 template<typename T> struct X { ... }; template<> struct X<int> { ... }; // ^^^^^ see, there have to be angle brackets after the identifier 

So,

 template<> void X::set(std::string &) { ... } 

doesn't specialize in anything, he implements

 class X { template<> void set(std::string &) { ... } }; 

which is a completely different function. I do not understand why gcc did not raise an error because the class does not have this member.

Now, even if you used the supposedly correct syntax, that would be wrong, because, as Tom already answered, you cannot specialize functions (just reload the version without the template). In C ++ 03, that is; it is allowed in C ++ 0x.

+3
source

What you want to use is overload.

 class X { public: void set( int v); //the case for ints void set( const std::string&) //the case for strings //The default catch all case. template< typename T > void set( T v ); }; //not a template specialisation. void X::set( int v ) { } //not a template specialisation. void X::set( const std::string & v ) { } //the catch all case template<typename T> void X::set(T v) { } 

Operators without templates will be selected in front of the template because they provide a better match if available. Otherwise, the template will be selected.

+2
source

All Articles