9

我有一个类似于这样的访客类:

struct Visitor 
{
    template <typename T>
    void operator()(T t)
    {
        ...
    }

    void operator()(bool b)
    {
        ...
    }
};

显然,operator()(bool b)它旨在成为上述模板函数的特化。

但是,它没有template<>我之前看到的语法,将其声明为模板特化。但它确实编译。

这安全吗?它是否正确?

4

5 回答 5

20

您的代码不是模板特化,而是非模板函数。那里有一些差异。非模板化的 operator() 将优先于模板化的版本(对于完全匹配,但类型转换不会在那里发生),但您仍然可以强制调用模板化函数:

class Visitor
{
public: // corrected as pointed by stefanB, thanks
   template <typename T>
   void operator()( T data ) {
      std::cout << "generic template" << std::endl;
   }
   void operator()( bool data ) {
      std::cout << "regular member function" << std::endl;
   }
};
template <> // Corrected: specialization is a new definition, not a declaration, thanks again stefanB 
void Visitor::operator()( int data ) {
   std::cout << "specialization" << std::endl;
}
int main()
{
   Visitor v;
   v( 5 ); // specialization
   v( true ); // regular member function
   v.operator()<bool>( true ); // generic template even if there is a non-templated overload
   // operator() must be specified there (signature of the method) for the compiler to 
   //    detect what part is a template. You cannot use <> right after a variable name
}

在您的代码中没有太大区别,但如果您的代码需要传递模板参数类型,它会变得更有趣:

template <typename T>
T g() { 
   return T();
}
template <>
int g() {
   return 0;
}
int g() {
   return 1;
}
int main()
{
   g<double>(); // return 0.0
   g<int>(); // return 0
   g(); // return 1 -- non-templated functions take precedence over templated ones
}
于 2009-06-01T22:48:07.450 回答
5

您在这里拥有的是函数重载;要获得模板专业化,您确实需要template <>语法。但是,您应该知道这两种方法,即使它们看起来相同,也有细微的不同,甚至编译器在选择要调用的正确函数时也可能会迷失方向。列出所有可能的情况对于这个答案来说有点太长了,但你可能想检查一下Herb Sutter GoTW #49关于这个问题。

于 2009-06-01T22:41:53.687 回答
4

哦,它会编译。它只是不会是模板功能。您将拥有一个常规的非模板函数,而不是模板特化。

它是安全的,实际上也可能是您想要的。访问者模式通常通过重载来实现。无论如何,专门化函数模板并不是一个好主意。

于 2009-06-01T22:27:07.680 回答
3

你做的不是模板序列化,而是函数重载。这是安全的。

PS很难说它是否正确,不知道你想要实现什么。请记住,无论是模板还是重载函数,都会在编译时选择您的运算符。如果需要运行时分派,则需要多态性,而不是重载。好吧,无论如何您可能都知道;以防万一。

于 2009-06-01T22:32:17.543 回答
2

你有

  • void operator()(bool b)那是非模板化的功能
  • template< typename T > void operator()(T t)这是一个单独的基础模板,重载了上述内容

您可以对第二个进行完全专业化,因为只有在不匹配template<> void operator(int i)时才会考虑。void operator()(bool b)

基础模板的特化用于选择调用哪个基础模板方法。但是,在您的情况下,您有一个将首先考虑的非模板化方法。

文章为什么不专门化函数模板?很好地解释了如何选择该方法。

总而言之:

  1. 首先考虑非模板函数(这是上面的普通 operator()(bool) )
  2. 其次检查函数基本模板(这是您的模板化函数),选择最专业的基本模板,然后如果它具有特定类型的专门化,则使用专门化,否则基本模板与“正确”类型一起使用(参见文章中的解释)

例子:

#include <iostream>
using namespace std;

struct doh
{
    void operator()(bool b)
    {
        cout << "operator()(bool b)" << endl;
    }

    template< typename T > void operator()(T t)
    {
        cout << "template <typename T> void operator()(T t)" << endl;
    }
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()<>(int i)
{
    cout << "template <> void operator()<>(int i)" << endl;
}
template<> void doh::operator()<>(bool b)
{
    cout << "template <> void operator()<>(bool b)" << endl;
}

int main()
{
    doh d;
    int i;
    bool b;
    d(b);
    d(i);
}

您会接到以下电话:

operator()(bool b)       <-- first non template method that matches
template <> void operator()(int i)     <-- the most specialized specialization of templated function is called
于 2009-06-01T23:11:34.250 回答