我遇到了一个方法专业化的奇怪问题。
鉴于此代码......
#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 )
,那么这将编译并链接正常。
答案 0 :(得分:3)
编译后恢复原始命题:
您对字符串的方法签名不应该是引用。应该是:
template<>
void X::set( const std::string v )
{
}
这是因为在您的模板定义中,您指定了T paramater
而不是T& paramater
答案 1 :(得分:3)
这完全是错误的语法。在专门化模板时,您必须将尖括号包含在您专门用于的类型中。 E.g:
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没有产生错误,因为该类没有该成员。
现在即使您使用了所谓的正确语法,也不正确,因为正如Tom已经回答的那样,无法专门化函数(只是重载非模板版本) )。在C ++ 03中,就是这样;在C ++ 0x中允许它。
答案 2 :(得分:2)
您想要使用的是重载。
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)
{
}
非模板运算符将在模板之前选择,因为它们提供了更好的匹配(如果可用)。否则将选择模板
答案 3 :(得分:2)
可能this article
将解释情况。
你可能期望专业化
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
}