Вывести нетипичный параметр шаблона
Можно ли вывести нетипичный параметр шаблона из параметра функции шаблона?
Рассмотрим этот простой шаблон:
template <int N> constexpr int factorial()
{
return N * factorial<N - 1>();
}
template <> constexpr int factorial<0>()
{
return 1;
}
template <> constexpr int factorial<1>()
{
return 1;
}
Я хотел бы иметь возможность изменить factorial
так что я могу альтернативно назвать это так:
factorial(5);
и пусть компилятор вычислит значение N во время компиляции. Это возможно? Может быть, с каким-нибудь необычным дополнением C++11?
6 ответов
Не может быть сделано, если у вас нет машины времени.
Параметр функции обрабатывается во время выполнения. Да, в вашем случае это буквальная константа, но это особый случай.
В определениях функций типы параметров фиксируются во время компиляции (и, следовательно, могут использоваться для определения параметров шаблона), но значения параметров фиксируются только во время выполнения.
Зачем тебе это нужно? Это просто, чтобы вам не нужно было печатать <>
"S?
Я полагаю, что ваш текущий код будет написан следующим образом:
constexpr factorial (int n)
{
return n > 0 ? n * factorial( n - 1 ) : 1;
}
Если вы называете это с помощью константного выражения, такого как factorial(5)
, тогда вся магия компилятора вступит в игру. Но если вы делаете int a = 3; factorial(a)
тогда я думаю, что он обратится к обычной функции - то есть он не построит таблицу поиска предварительно вычисленных ответов.
В общем, вы должны пометить каждую функцию и конструктор как constexpr
если ты можешь. Вы ничего не теряете, компилятор будет обрабатывать его как обычную функцию, если это необходимо.
Я не думаю, что вы можете сделать это; единственный способ сделать это - иметь constexpr
параметр функции, который будет передан тогда как template
параметр для шаблонной версии factorial
, но constexpr
параметры функции не допускаются.
Нет, ты не можешь этого сделать. Аргументы шаблона могут быть выведены только из типа аргумента функции, а не значения, которое обычно не будет известно во время компиляции.
Конечно, вы могли бы переписать factorial
как не шаблон constexpr
функция; тогда это будет оценено во время компиляции, если аргумент известен тогда.
Нет, это невозможно, если вы не хотите создать огромный оператор switch:
int getFactorial( const int v )
{
switch ( v )
{
case 1 : return factorial<1>();
case 2 : return factorial<2>();
//etc
default:
;
}
return 0;
}
Одно из возможных обходных решений для такого рода проблем - использовать некоторые struct
нравится:
template <int X>
struct constant {
operator int () { return X; }
};
Тогда у нас может быть перегрузка constant<X>
нравится:
template <int X>
void f (constant<X>)
Использование стоимости X
при перегрузках во время компиляции и выполнения f (int)
. Раздражает то, что это требует определенной дисциплины на сайте вызова, поскольку каждая буквальная константа должна быть обернута какconstant<X> {}
(с макросом или чем-то вроде этого).