奇怪的c++模板方法专业化问题

发布于 2024-11-26 10:44:42 字数 864 浏览 1 评论 0 原文

我在方法专业化方面遇到了一个奇怪的问题。

鉴于此代码...

#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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

江挽川 2024-12-03 10:44:42

这是完全错误的语法。当专门化模板时,您必须包含尖括号以及您专门化的类型。例如:

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 中允许这样做。

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.

秋意浓 2024-12-03 10:44:42

编译后恢复到原始命题:

字符串的方法签名不应该是引用。应该是:

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

这是因为在模板定义中您指定了 T paramater 而不是 T&参数

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

柠檬色的秋千 2024-12-03 10:44:42

可能是这篇文章
会解释情况。

您可能期望专业化
void X::set( const std::string& ) 将参与重载
解决。
然而,令人惊讶的是,
专业化不参与重载解析。

在调用x.set( y )中,编译器推导主函数中T的类型
来自参数 y 的模板,类型为 std::string
因此,编译器推断 Tstd::string,然后搜索匹配的
专业化。

但是,由于 std::stringconst 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
}

Probably this article
will explain the situation.

You might expect the specialization
void X::set( const std::string& ) will participate in overload
resolution.
However, surprisingly,
specializations don't participate in overload resolution.

In the call x.set( y ), the compiler deduces the type of T in the primary
template from the argument y with a type std::string.
So, the compiler deduces that T is std::string, then searches matching
specialization.

However, since std::string and const 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 selected
is similar to that the specialization A< std::string > isn't 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
}
安稳善良 2024-12-03 10:44:42

你想要使用的是重载。

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

非模板运算符将在模板之前选择,因为它们提供更好的匹配(如果可用)。否则将选择模板

What you want to use is overloading.

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文