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