Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strange c++ template method specialisation issue

I've come across a strange problem with method specialisation.

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 link it with g++ 4.3.3 I get an undefined reference 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> >).

Which is basically an undefined reference to void X::set( std::string ).

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

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

like image 260
ScaryAardvark Avatar asked Dec 28 '22 16:12

ScaryAardvark


2 Answers

It's altogether incorrect syntax. When specializing templates, you have to include the angle brackets with the types you are specializing for. E.g.:

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 &) { ... }

is not specializing anything, it is implementing

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

which is altogether different function. What I don't understand is why gcc didn't produce an error because the class does not have that member.

Now even if you used the supposedly-correct syntax, it wouldn't be correct, because, as already answered by Tom, you can't specialize functions (just overload with non-template version). In C++03, that is; it is allowed in C++0x.

like image 61
Jan Hudec Avatar answered Dec 30 '22 06:12

Jan Hudec


Reverting back to original proposition after compilation:

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

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

This is because in your template definition you have specified T paramater and not T& paramater

like image 20
Adrian Regan Avatar answered Dec 30 '22 04:12

Adrian Regan