#c #templates #c 14 #variadic-templates #sfinae
#c #шаблоны #c 14 #variadic-шаблоны #sfinae
Вопрос:
Я пытаюсь написать такую функцию, которая f<T>(args..)
возвращает первый параметр типа T
.
Следующая программа, похоже, всегда выбирает первую специализацию, таким образом печатая 97
(ASCII-код 'a'
). Хотя второй не требует преобразования char
в int
. Не мог бы кто-нибудь объяснить поведение?
Я новичок в SFINAE и мета-программировании.
#include <iostream>
using namespace std;
template <typename T, typename ...Ts>
T f(T a, Ts... args) {
return a;
}
template <typename R, typename T, typename ...Ts>
R f(typename enable_if<!is_same<R, T>::value, T>::type a, Ts... args) {
return f<R>(args...);
}
int main() {
cout << f<int>('a', 12);
}
Комментарии:
1. Что вы на самом деле собираетесь делать во 2-й перегрузке
f
?
Ответ №1:
Вторым аргументом шаблона std::enable_if
должен быть the R
, который вы хотите иметь.
Следующее должно работать
template < typename R, typename T, typename ...Ts>
typename enable_if<!is_same<R, T>::value, R>::type f(T constamp; t, Tsamp;amp;... args)
// ^^^ ^^^^^^^^^^^
{
return f<R>(std::forward<Ts>(args)...); // forward the args further
}
Комментарии:
1. спасибо за ваш ответ. Было бы очень полезно, если бы вы объяснили, чем отличается этот код. Мне кажется, что оба они должны работать, поскольку цель состоит в том, чтобы просто сделать один тип зависимым от
is_same<R, T>
, чтобы, когда они действительно одинаковы, вышеуказанная специализация не учитывалась.2. @AbhishekKumar — проблема с вашим исходным кодом заключается в том, что тип
T
intypename enable_if<!is_same<R, T>::value, T>::type a
не выводится (T
находится в «не выводимом контексте»; упрощение: находится перед::
), поэтому рекурсивная версия никогда не включается). Это решение позволяетT
вычитать изa
аргумента, поэтому SFINAE работает так, как задумано.
Ответ №2:
Первый функциональный параметр вашего кода находится в неразведенном контексте. не enable_if< expr, T >::type
удается вывести T
. Он находится в «неразведенном контексте».
Будучи не в состоянии вывести T
, foo<int>( 7 )
не может использовать эту перегрузку; компилятор не знает, что T
такое. foo<int,int>(7)
вызовет его.
template <typename R, typename T, typename ...Ts>
typename enable_if<!is_same<R, T>::value, R>::type f(T a, Ts... args)
now T
находится в выведенном контексте. Мы не пытаемся вывести R
(и не можем вывести из возвращаемого типа).