Почему не могут нестатические члены данных быть constexpr?

Это действительный код:

struct S { constexpr S(int x, int y): xVal(x), yVal(y) {} constexpr S(int x): xVal(x) {} constexpr S() {} const int xVal { 0 }; const int yVal { 0 }; }; 

Но здесь я бы очень хотел объявить xVal и yVal constexpr например:

 struct S { constexpr S(int x, int y): xVal(x), yVal(y) {} constexpr S(int x): xVal(x) {} constexpr S() {} constexpr int xVal { 0 }; // error! constexpr int yVal { 0 }; // error! }; 

Как указано, код не будет компилироваться. Причина в том, что (на 7.1.5 / 1), только статические члены данных могут быть объявлены constexpr . Но почему ?

Подумайте, что означает constexpr . Это означает, что я могу разрешить это значение во время компиляции.

Таким образом, переменная-член classа не может сама быть constexpr … экземпляр, к xVal принадлежит xVal , не существует до момента создания экземпляра! Вещь, которой принадлежит xVal может быть constexp , и это сделает xVal constexpr , но xVal никогда не может быть constexpr самостоятельно.

Это не означает, что эти значения не могут быть const-выражением … на самом деле, экземпляр constexpr classа может использовать переменные как выражения const:

 struct S { constexpr S(int x, int y): xVal(x), yVal(y) {} constexpr S(int x): xVal(x) {} constexpr S() {} int xVal { 0 }; int yVal { 0 }; }; constexpr S s; template //requires a constexpr int foo() {return f;} int main() { cout << "Hello World" << foo( )<< endl; return 0; } 

Редактировать: Таким образом, было много обсуждений ниже, которые были рассмотрены, что здесь было несколько подразумеваемых вопросов.

«Почему я не могу принуждать все экземпляры classа к constexpr, объявляя его члены constexpr?»

Возьмем следующий пример:

 //ah struct S; struct A {std::unique_ptr x; void Foo(); A();/*assume A() tries to instantiate an x*/} //main.cpp int main(int argc, char** argv) { A a; a->foo(); } //Sh struct S { constexpr S(int x, int y): xVal(x), yVal(y) {} constexpr S(int x): xVal(x) {} constexpr S() {} constexpr int xVal { 0 }; // error! constexpr int yVal { 0 }; }; 

Определение A и S может быть в совершенно разных единицах компиляции, поэтому факт, что S должен быть constexpr, может не быть известен до времени ссылки, особенно если реализация A забыта. Такие неоднозначные случаи трудно отлаживать и их трудно реализовать. Хуже всего то, что интерфейс для S может быть полностью открыт в общей библиотеке, интерфейсе COM, ect ... Это может полностью изменить все инфраструктуры для общей библиотеки, и это, вероятно, будет неприемлемым.

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

 //Sh struct S { constexpr S(int x, int y): xVal(x), yVal(y) {} constexpr S(int x): xVal(x) {} constexpr S() {} constexpr int xVal { 0 }; // error! int yVal { 0 }; }; 

Любой экземпляр S должен быть constexpr чтобы иметь возможность содержать исключительно constexpr xval . yVal своей сути становится constexpr поскольку xVal . У вас нет технической причины компилятора, вы не можете этого сделать (я не думаю), но он не очень похож на C ++.

«ОК, но я REEAAALLLY хочу сделать все экземпляры classа constexpr. Какое техническое ограничение мешает мне делать это».

Наверное, ничего, кроме комитета по стандартам, не думал, что это хорошая идея. Лично я считаю, что у него очень мало полезности ... Я действительно не хочу определять, как люди используют мой class, просто определите, как ведет себя мой class, когда они его используют. Когда они используют его, они могут объявлять конкретные экземпляры как constexpr (как указано выше). Если у меня есть какой-то блок кода, для которого мне бы понадобился экземпляр constexpr, я бы сделал это с помощью шаблона:

 template  function int bar(){return s.xVal;} int main() { cout << "Hello World" << foo()>( )<< endl; return 0; } 

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

 constexpr int bar(S s) { return s.xVal; }