模板专精化需要模板<>句法?

时间:2009-06-01 22:22:36

标签: c++ templates syntax template-specialization

我有一个类似于此的访客类:

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

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

显然, operator()(bool b) 旨在成为上述模板功能的专业化。

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

这样安全吗?这是对的吗?

5 个答案:

答案 0 :(得分:19)

您的代码不是模板专业化,而是非模板化的功能。那里有一些差异。非模板化的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
}

答案 1 :(得分:5)

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

答案 2 :(得分:4)

哦,它会编译。它不会是模板功能。您将拥有常规的非模板功能,而不是模板专业化。

这是安全的,实际上也可能是你想要的。访问者模式通常通过重载来实现。专业化功能模板isn't really a good idea anyway.

答案 3 :(得分:2)

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

P.S。在不知道你想要实现的目标的情况下,很难说它是否正确。请记住,无论是模板还是重载函数,都会在编译时选择运算符。如果需要运行时调度,则需要多态,而不是重载。好吧,无论如何你可能都知道;以防万一。

答案 4 :(得分:2)

你有

  • void operator()(bool b)不是 模板化功能
  • template< typename T > void operator()(T t)这是一个单独的 重载的基本模板 上述

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

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

文章Why Not Specialize Function Templates?非常好地解释了如何选择该方法。

在sumary:

  1. 非模板功能 首先考虑(这是你的平原 operator()(bool)上面)
  2. 检查功能库模板 第二(这是你的模板 函数),选择最专业的基本模板,然后如果它对使用特化的确切类型有专门化,否则基本模板与“正确”类型一起使用(参见文章中的解释)
  3. 示例:

    #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