2009-06-01 2 views
8

У меня есть класс посетителя, напоминающее это:Требуется ли шаблонная специализация шаблона <> синтаксиса?

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

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

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

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

Безопасно ли это? Это верно?

ответ

19

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

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 
} 
+0

Я считаю, что "template <> void operator() (int data) {" в верхнем разделе кода должен быть "template <> void operator() (int data) {", а в нижней части "int g() {"должно быть" int g () {"внизу (извините, я не знаю, как стилизовать разделы кода в комментариях) –

+0

У меня были сомнения, но оба компилятора GCC и Comeau принимают код как действительный. Я не могу протестировать MSVS сейчас, если вы можете попробовать, я был бы признателен :) –

+0

по-прежнему смотри здесь ответ http://stackoverflow.com/questions/937744/function-template-specialization-format – stefanB

4

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

Это безопасно и на самом деле вероятно, что вы хотите. Шаблон посетителя обычно реализуется путем перегрузки. Специализированные шаблоны функций isn't really a good idea anyway.

+0

Существуют ситуации, в которых он будет вести себя по-другому? Это потенциальная ошибка или просто плохой стиль? –

+0

Обычно это правильная вещь. Обычно вы предпочитаете простые перегрузки над специализациями шаблонов функций. Поведение более предсказуемо. – jalf

+0

+1 за ссылку, именно то, что я искал. – avakar

2

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

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

5

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

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. Номер функций шаблонных считаются первыми (это ваш обычный оператора() (Его) выше)
  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 
+2

Вы пропустили аргумент brackets: template <> void doh :: operator() <> (bool b) (обратите внимание на вставленный «<>» i) и обратите внимание, что он (sutter) явно пишет, что наиболее специализированный базовый шаблон . Не «тот, у кого самая соответствующая специализация», ни «самая специализированная специализация шаблонной функции». В резолюции явно рассматриваются только первичные (базовые) шаблоны. Это называется «частичным упорядочением функциональных шаблонов» и описывается в стандарте 14.6.6.2. –

+0

Вы правы в выборе базовых шаблонов, я думаю, что я коротко замыкал это мое объяснение (ленивый ввод?), Я пытался сказать, что выбран самый специализированный базовый шаблон, а затем, если у него есть специализация для точных типов, которые специализация используется иначе базовый шаблон используется с «правильными» типами – stefanB

+0

На gcc3.3.3 оба с скобками шаблон <> void doh :: operator() <> (bool b) и без шаблона форм <> void doh :: operator() (bool b) скомпилировать и дал мне тот же результат, все еще скопируйте/вставьте в примере от @dribeas появится ошибка ошибок: явная специализация в области без пространства имен 'struct doh 'и т. д. - вот что я имел в виду (и потому что методы все частные, но это на стороне примечания) – stefanB

Смежные вопросы