我在方法专业化方面遇到了一个奇怪的问题。
鉴于此代码...
#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::allocator; > >(std::basic_string、std::allocator>)。
这基本上是对 void X::set( std::string )
的未定义引用。
所以我的问题是,为什么编译器不使用 const std::string &
的专业化?
如果我显式调用 x.set<常量 std::string & >( y )
然后编译和链接就可以了。
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.
发布评论
评论(4)
这是完全错误的语法。当专门化模板时,您必须包含尖括号以及您专门化的类型。例如:
所以
不是专门做任何事情,而是实现
完全不同的功能。我不明白的是为什么 gcc 没有产生错误,因为该类没有该成员。
现在,即使您使用了所谓正确的语法,它也不会是正确的,因为,正如汤姆已经回答的那样,您不能专门化函数(只是用非模板版本重载)。在 C++03 中,即; C++0x 中允许这样做。
It's altogether incorrect syntax. When specializing templates, you have to include the angle brackets with the types you are specializing for. E.g.:
So
is not specializing anything, it is implementing
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.
编译后恢复到原始命题:
字符串的方法签名不应该是引用。应该是:
这是因为在模板定义中您指定了
T paramater
而不是T&参数
Reverting back to original proposition after compilation:
Your method signature for string should not be a reference. Should be:
This is because in your template definition you have specified
T paramater
and notT& paramater
可能是这篇文章
会解释情况。
您可能期望专业化
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 > 未选择
在下面的代码中:
Probably this article
will explain the situation.
You might expect the specialization
void X::set( const std::string& )
will participate in overloadresolution.
However, surprisingly,
specializations don't participate in overload resolution.
In the call
x.set( y )
, the compiler deduces the type ofT
in the primarytemplate from the argument
y
with a typestd::string
.So, the compiler deduces that
T
isstd::string
, then searches matchingspecialization.
However, since
std::string
andconst std::string&
are different types,the compiler selects primary template in the end.
After proper primary template is selected, the matching specialization is
selected in the same manner as the case for class template.
The reason that the specialization
set( const std::string& )
isn't selectedis similar to that the specialization
A< std::string >
isn't selectedin the following code:
你想要使用的是重载。
非模板运算符将在模板之前选择,因为它们提供更好的匹配(如果可用)。否则将选择模板
What you want to use is overloading.
The non-template operators will be chosen ahead of the template because they provide a better match if available. Otherwise the template will be chosen