2012-01-12 3 views
5

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

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

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?

+0

Почему вы хотите это сделать? Функция 'factorial' не принимает никаких параметров.В чем преимущество 'factorial (5)' над правильным 'factorial <5>()'? –

+0

@CodyGray: Я думаю, что идея заключалась бы в создании универсальной «факториальной» функции, способной вычислять результат во время компиляции, если ему дано выражение, известное во время компиляции, но также способное вычислять его во время выполнения, если вход нормальная переменная. –

+0

@Matteo: Насколько я понимаю, во время выполнения ничего не вычисляется, поскольку выражение объявлено 'constexpr'. И вообще, я не понимаю, почему возникла бы проблема с передачей «нормальной переменной» вместо 5 с использованием стандартного синтаксиса. Вопрос здесь в том, «как я могу избежать набора угловых скобок», и я не понимаю мотивацию. –

ответ

4

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

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

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

Зачем вам это нужно? Это просто так, что вам не нужно вводить <>?

+0

В значительной степени у меня есть огромная база кода с вызовами нескольких функций, которые я переписал в качестве шаблона. Замена имен тривиальна, но все символы f (2, 3, "abc", true) 'в' f <2, 3, true> ("abc") 'немного сложнее. – pezcode

+1

Как насчет макроса для преобразования 'f (2, 3," abc ", true)' в 'f_impl <2, 3, true> (" abc ")'? –

1

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

0

Нет, это не возможно, если вы не хотите, чтобы создать огромное заявление переключателя:

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

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

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

8

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

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

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

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

+1

Я не знал, что Constexpr работает так. К сожалению, код является всего лишь примером, и мне нужен массив фиксированного размера внутри фактической функции, поэтому мне нужен шаблон с размером массива в качестве параметра. – pezcode

+0

Возможно, вы построили массив указателей функций для шаблонных функций во время компиляции и просмотрите их во время выполнения? 'factorial [3] (.. other args ..)' –

+0

@pezcode: изменить factorial на макрос, который вызывает код шаблона, Aaron: youd лучше построить массив результатов –

0

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

#define factorial(X) factorial<X>() 
Смежные вопросы