Вывести нетипичный параметр шаблона

Можно ли вывести нетипичный параметр шаблона из параметра функции шаблона?

Рассмотрим этот простой шаблон:

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 если ты можешь. Вы ничего не теряете, компилятор будет обрабатывать его как обычную функцию, если это необходимо.

Используйте злой макрос:

#define factorial(X) factorial<X>()

Я не думаю, что вы можете сделать это; единственный способ сделать это - иметь 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> {} (с макросом или чем-то вроде этого).

Другие вопросы по тегам