странный вопрос специализации метода шаблона c++


Я столкнулся со странной проблемой со специализацией метода.

Приведенный код...

#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 );
}

Когда я связываю его с g++ 4.3.3, я получаю неопределенную ссылку на 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> >).

, которая в основном является неопределенной ссылкой на void X::set( std::string ).

Итак, мой вопрос в том, почему компилятор не использует специализацию с const std::string &?

Если я явно вызываю x.set< const std::string & >( y ) , то это прекрасно компилируется и связывается.

4   4   2011-07-25 14:46:32

4 ответа:

Вероятно Эта статья объясню ситуацию.
можно ожидать специализации void X::set( const std::string& ) будет участвовать в перегрузке разрешение. Однако, удивительно, специализации не участвуют в разрешении перегрузки.
в вызове x.set( y ) компилятор выводит Тип T в первичном шаблон из аргумента y с типом std::string. Таким образом, компилятор выводит, что T является std::string, а затем ищет соответствие специализация.
однако, поскольку std::string и const std::string& являются различные формы, в конце компилятор выбирает основной шаблон.

После того, как выбран правильный первичный шаблон, соответствующая специализация выбирается так же, как и в случае с шаблоном класса. Причина в том, что специализация set( const std::string& ) Не выбрана похоже на то, что специализация A< std::string > Не выбрана в следующем коде:

template< class > class A; // primary

template<> class A< const std::string& > {}; // specialization

int main() {
  A< std::string > a; // This doesn't select the specialization
}

Это совершенно неправильный синтаксис. Когда вы специализируетесь на шаблонах, вы должны включать угловые скобки с типами, на которые вы специализируетесь. Например:

template<typename T>
struct X { ... };

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

Итак

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

Не специализируется ни на чем, он реализует

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

Которая является совершенно другой функцией. Чего я не понимаю, так это почему gcc не выдал ошибку, потому что у класса нет этого члена.

Теперь, даже если вы используете предположительно правильный синтаксис, он не будет правильным, потому что, как уже ответил Том, Вы не можете специализировать функции (просто перегружайте их не шаблонной версией). В C++03, то есть; это разрешено в C++0x.

Возвращаясь к исходному предложению после компиляции:

Ваша сигнатура метода для string не должна быть ссылкой. Должно быть:

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

Это потому, что в определении шаблона вы указали T paramater, а не T& paramater

То, что вы хотите использовать, - это перегрузка.

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

Операторы, не являющиеся шаблоном, будут выбраны раньше шаблона, поскольку они обеспечивают лучшее соответствие, если оно доступно. В противном случае будет выбран шаблон