2014-10-27 3 views
12

Я играю с некоторым кодом игрушек, используя C++ 11, чтобы узнать немного больше о том, как все работает. Во время этого я наткнулся на следующий вопрос, который упрощает вниз:Параметры функции constexpr как аргументы шаблона

template <int x, int y> 
class add { 
public: 
    static constexpr int ret = x + y; 
}; 

constexpr int addFunc(const int x, const int y) { 
    return add<x,y>::ret; 
} 

int main() { 
    const int x = 1; 
    const int y = 2; 
    cout << add<x,y>::ret << endl; // Works 
    cout << addFunc(1,2) << endl; // Compiler error 
    return 0; 
} 

Я использую GCC 4.8.1, а выход:
«х» не является константным выражением в шаблоне аргумента для типа «INT '
„у“ не является постоянным выражением в шаблоне аргумента для типа „INT“

Что именно разница между этими двумя способами я пытаюсь вычислить add::ret? Оба эти значения должны быть доступны во время компиляции.

+3

Функции 'constexpr' должны выполняться во время выполнения. – chris

+1

Ну ... да. Так почему конкретно это невозможно оценить во время компиляции? – Danny

+6

Чтобы разработать: 'constexpr' функции должны быть запущены во время выполнения, и ваша функция' constexpr' будет терпеть неудачу при вызове с любым значением, которое не является константой времени компиляции, поэтому ваша функция 'constexpr' недействительна , То, что вы ищете, не то, что предоставляет 'constexpr', и это не то, что предлагает C++ в другой форме. То, что ближе всего, делает 'addFunc' функцию шаблона с параметрами шаблона' int x' и 'int y'. – hvd

ответ

7

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

Существует способ, вы можете сделать компилятор понять, вы только собираетесь передать компиляции константы времени для addFunc: Сделайте параметры а параметры шаблона себя:

template <int x, int y> 
constexpr int addFunc() { 
    return add<x,y>::ret; 
} 

Тогда звоните в

cout << addFunc<1,2>() << endl; 
5

Компилятор не знает, что x и y всегда доступны во время компиляции как постоянные значения (выражение), и что еще, C++ 11/14 не поддерживает параметр функции constexpr, поэтому нет способа x и y можно использовать как параметр для шаблона add <> в addFunc.

7

Если ваша цель просто сократить код немного, в C++ 14 вы можете создать переменный шаблон:

template <int x, int y> 
constexpr int addVar = x + y; 

cout << addVar<5, 6> << endl; // Works with clang 3.5, fails on GCC 4.9.1 

will also support this GCC 5.

3

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

Шаблон-аргументы требуют постоянных выражений. Это важные требования для постоянных выражений, которые не выполняются в коде и, таким образом, производят ошибку компилятора ([expr.const]/2, курсив мой):

условное выражение является ядро константы если ней не включает в себя одно из следующих действий как потенциально оцениваемая подвыражению (3.2) [...]:

- именующие к Rvalue преобразование (4.1), если оно не применяется к

  • в glvalue интегрального или перечисления типа, который ссылается на энергонезависимую объекта сопзЬ с предыдущей инициализации, инициализируется с постоянным выражением, или
  • glvalue из буквальным типа, который относится к энергонезависимому объекту определенного с constexpr, или, что относится к подобъекту такого объекта или
  • glvalue буквального типа, который относится к энергонезависимому временного объекту срок службы которого не закончился, инициализируется постоянным выражением ;

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