2009-04-09 2 views
4

У меня есть шаблонный шаблон и внутри у меня есть шаблонная функция (разные параметры шаблона), и у меня возникают проблемы с тем, чтобы компилятор вызывал правильный.Шаблон Специализация функции внутри Templated Class

Пример:

template< class Parm1, class Parm2, class Parm3 > 
class Class { 
public: 
    void Func(Parm1 arg1, Parm2 arg2) { 
     Call<Parm3>(arg1, arg2); 
    } 

protected: 
    template< class Type > 
    void Call(Parm1 arg1, Parm2 arg2) { 
    } 

    template<> 
    void Call<void>(Parm1 arg1, Parm2 arg2) { 
    } 
}; 

Так, если тип Parm3 является «пустота» Я хочу, чтобы второй вызов будет называться. В противном случае первое. VS работает отлично, но GCC pukes все это. Он всегда вызывает первый. Теперь это проблема со специализацией внутри неспециализированного класса или это связано с тем, что Im, специализирующийся на «void»

Любая помощь будет отличной. Благодарю.

ответ

7

Да, явно специализация функции без полной специализации всего внешнего шаблона невозможна (явная специализированная функция - это реальная функция - не может быть никаких «переменных частей» вокруг нее, которые все еще параметризуются шаблоном)

простой способ заключается в использовании шаблона type2type вместе с перегрузкой:

template<typename T> struct t2t { typedef T type; }; 

void Func(Parm1 arg1, Parm2, arg2) { Call<Parm3>(arg1, arg2, t2t<Parm3>()); } 
template< class Type, class V > void Call(Parm1 arg1, Parm2 arg2, t2t<V>) { } 
template< class Type > void Call(Parm1 arg1, Parm2 arg2, t2t<void>) { } 

Теперь он будет вызывать второй Call перегрузку, если вы звоните его t2t<void>, и первый в противном случае, поскольку первый из них меньше особый.

Использование enable_if можно также:

void Func(Parm1 arg1, Parm2, arg2) { Call<Parm3>(arg1, arg2); } 

template< class Type > typename disable_if< is_same<Type, void> >::type 
Call(Parm1 arg1, Parm2 arg2) { } 

template< class Type > typename enable_if< is_same<Type, void> >::type 
Call(Parm1 arg1, Parm2 arg2) { } 

Теперь, второй один берется, если Type является недействительным, и первый один берется, если Type что-то еще раз. Но с использованием другой техники. Это называется SFINAE. Альтернативный способ, но снова добавляет один параметр это - продемонстрировать, как SFINAE работает:

void Func(Parm1 arg1, Parm2, arg2) { Call<Parm3>(arg1, arg2); } 

template< class Type > 
void Call(Parm1 arg1, Parm2 arg2, char(*)[!is_same<Type, void>::value] = 0) { } 

template< class Type > 
void Call(Parm1 arg1, Parm2 arg2, char(*)[ is_same<Type, void>::value] = 0) { } 

SFINAE происходит, если замещение выходов параметров шаблона недопустимого типа или построить. Ниже мы пытаемся создать указатель на массив размером 0 или 1 соответственно. Массив размера 0 недействителен и вызовет сбой SFINAE. Соответствующая спецификация шаблона не будет считаться кандидатом на вызов, если это функция.

В случае с enable_if этот товар отличается. Если enable_if получает что-то, полученное от false_type, то оно делает его ::type typedef не существует. is_same происходит от false_type в случае, если типы не совпадают. Затем мы попытаемся получить доступ к несуществующему имени, которое является недопустимой конструкцией, и для этого также должен быть сбой SFINAE.

+0

Очень интересная информация на листе, но у меня возникают проблемы с кодом - существуют ли функции Func() и Call() внутри класса? –

+0

да. я удалил заметку сейчас :) Я имел в виду этот комментарий только для t2t, потому что он полезен и для других случаев и может быть определен в каком-то пространстве имен приложений :) –

+0

Я вижу, очень умно! (Пришло время выяснить, что именно происходит там ...) Правильно ли я полагаю, что вы используете t2t на всякий случай, если V либо большой, либо не имеет значения по умолчанию ctor? Кстати, это прояснит ситуацию, если вы можете поместить последние 3 строки фрагмента №1 в определение класса. –

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