Компилятор четко объяснил вам, в чем проблема: в объявлении шаблона вы указали дополнительный тип-тип шаблона, который не может быть выведен.Как вы ожидаете, что компилятор выведет правильное значение для этого нетипового параметра?От чего?
Именно поэтому вышеупомянутая техника для использования std::enable_if
требует аргумента по умолчанию.Это фиктивный параметр, поэтому значение аргумента по умолчанию не имеет значения (0
- это естественный выбор).
Вы можете сократить ваш пример до простого
template <typename T, T x>
void foo(T t) {}
int main()
{
foo(42);
}
Производство
error: no matching function for call to 'foo(int)'
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter 'x'
Компилятор может определить, что такое T
(T == int
), но компилятор не может определить аргумент для x
.
Ваш код точно такой же, за исключением того, что ваш второй параметр шаблона остался безымянным (не нужно давать имя фиктивному параметру).
Судя по вашим комментариям, вы, кажется, смущены присутствием ключевого слова typename
в объявлении второго параметра в вашем коде, который заставляет вас поверить, что второй параметр также является параметром type .Последнее не соответствует действительности.
Обратите внимание, что в объявлении второго параметра ключевое слово typename
используется в совершенно другой роли .Это ключевое слово просто устраняет неоднозначность семантики
std::enable_if<std::is_class<T>::value, T>::type
. Оно сообщает компилятору, что вложенное имя type
фактически представляет собой имя типа , а не чего-то другого.(Вы можете прочитать об этом использовании typename
здесь: Зачем нам здесь имя типа? и Где и почему я должен поставить ключевые слова "template" и "typename"? )
Использование typename
не превращает второй параметр вашего шаблона в параметр type .Вторым параметром вашего шаблона по-прежнему является не тип параметр.
Вот еще один упрощенный пример, который иллюстрирует, что происходит в вашем коде
struct S { typedef int nested_type; };
template <typename T, typename T::nested_type x>
void bar(T t)
{}
int main()
{
S s;
bar<S, 42>(s);
}
Обратите внимание, что даже еслиобъявление второго параметра начинается с typename
, оно все еще объявляет параметр не-типа.