Вывести нетипичный параметр шаблона - PullRequest
6 голосов
/ 12 января 2012

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

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

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 ]

8 голосов
/ 12 января 2012

Ваш текущий код обычно записывается следующим образом:

constexpr factorial (int n)
{
    return n > 0 ? n * factorial( n - 1 ) : 1;
}

Если вы вызываете его с помощью константного выражения, такого как factorial(5), тогда вся магия компилятора вступит в игру. Но если вы сделаете int a = 3; factorial(a), то я думаю, что он прибегнет к обычной функции - то есть не будет построена таблица поиска предварительно вычисленных ответов.

В общем, вы должны пометить каждую функцию и конструктор как constexpr, если можете. Вы ничего не потеряете, компилятор при необходимости сочтет это нормальной функцией.

5 голосов
/ 12 января 2012

Невозможно сделать, если у вас нет машины времени.

Параметр функции обрабатывается во время выполнения.Да, в вашем случае это буквальная константа, но это особый случай.

В определениях функций параметр types фиксируется во время компиляции (и поэтому, может использоваться для вывода параметров шаблона), но значения параметров фиксируются только во время выполнения.

Зачем вам это нужно?Вы просто не должны печатать <>?

1 голос
/ 12 января 2012

Я не думаю, что вы можете сделать это; единственный способ сделать это - иметь параметр функции constexpr, который затем будет передан как параметр template для версии шаблона factorial, но параметры функции constexpr не допускаются.

0 голосов
/ 25 мая 2016

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

#define factorial(X) factorial<X>()
0 голосов
/ 12 января 2012

Нет, вы не можете этого сделать. Аргументы шаблона могут быть получены только из типа аргумента функции, а не из значения , которое обычно не будет известно во время компиляции.

Конечно, вы можете переписать factorial как не шаблонную constexpr функцию; тогда он будет оценен во время компиляции, если аргумент известен тогда.

0 голосов
/ 12 января 2012

Нет, это невозможно, если вы не хотите создать огромный оператор switch:

int getFactorial( const int v )
{
  switch ( v )
  {
    case 1 : return factorial<1>();
    case 2 : return factorial<2>();
    //etc
    default:
       ;
  }
  return 0;
}
...