Требуются ли для шаблонов специализации шаблона <> синтаксис?

StackOverflow https://stackoverflow.com/questions/937107

Вопрос

У меня есть класс посетителей, напоминающий это:

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

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

Четко, operator()(bool b) предназначен для специализации предыдущей функции шаблона.

Однако у него нет template<> Синтаксис, который я привык видеть перед ним, объявляя об этом как специализацию шаблона. Но это компилируется.

Это безопасно? Это правильно?

Это было полезно?

Решение

Ваш код не является специализацией шаблона, а скорее неэлементной функцией. Там есть некоторые различия. Оператор без размера () будет иметь приоритет по сравнению с шаблонной версией (для точного совпадения, но преобразования типа там не будут иметь место), но вы все равно можете вызвать называться шаблонную функцию:

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
}

Другие советы

То, что у вас есть, это перегрузка функций; Чтобы получить специализацию шаблонов, вам действительно нужна template <> синтаксис. Тем не менее, вы должны знать, что эти два подхода, даже если они могут показаться идентичными, тонко разные, и даже компилятор может потеряться при выборе правильной функции для вызова. Перечисление всех возможных случаев было бы слишком долго для этого ответа, но вы можете проверить Херб Саттер ГОТУ #49 по этому вопросу.

О, это будет компилировать. Это просто не будет функцией шаблона. У вас будет регулярная функция, не относящаяся к T-Template, вместо специализации шаблона.

Это безопасно, и на самом деле вероятно, что вы хотите. Образец посетителя обычно реализуется путем перегрузки. Специализирующие шаблоны функций В любом случае, не очень хорошая идея.

То, что вы сделали, это не сериализация шаблона, а перегрузка функций. Это безопасно.

PS Трудно сказать, правильно ли это или нет, не зная, чего вы пытаетесь достичь. Имейте в виду, что независимо от того, что это шаблон или перегруженная функция, ваш оператор будет выбран во время компиляции. Если вам нужно отправить время выполнения, вам нужен полиморфизм, а не перегрузка. Ну, вы, наверное, знаете это все равно; на всякий случай.

У вас есть

  • void operator()(bool b) это не шаблонная функция
  • template< typename T > void operator()(T t) который является отдельным базовым шаблоном, который перегружает вышеупомянутое

Вы могли бы иметь полную специализацию второго, как в template<> void operator(int i) что будет рассматриваться только тогда, когда void operator()(bool b) не совпадал.

Специализация базового шаблона используется для выбора того из методов базового шаблона. Однако в вашем случае у вас есть неэлементный метод, который будет рассмотрен в первую очередь.

Статья Почему бы не специализировать шаблоны функций? дает довольно хорошее объяснение того, как выбран метод.

В Sumary:

  1. Функции, не являющиеся шаблонами, считаются первыми (это ваш обычный оператор () (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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top