2017-01-10 10 views
12

стандарт C++ специфически запрещает вызывая new в постоянном выражении (раздел N4296 5.20 [expr.const]):Constexpr размещение новое?

Условное выражение Е является постоянным выражением ядра, если при оценке е, следуя правилам абстрактная машина (1,9), будет оценивать одно из следующих выражений:

...

- новое выражение (5.3.4);

Этот запрет (насколько я могу судить) распространяется на все формы new, в том числе размещения нового. Однако, поскольку размещение new фактически не выделяет какую-либо память и просто запускает конструкторы в данном месте, и поскольку правомерно принимать адрес переменной в контексте constexpr (действительно, std::addressof будет constexpr в C++ 17), мне кажется, что этот запрет можно (в принципе, по крайней мере) облегчить, чтобы позволить размещение новых функций constexpr.

Так что мой вопрос: я чего-то не хватает? Есть ли веская причина, почему размещение новых запрещено в функциях constexpr?

(Для контекста: текущие правила в значительной степени требуют, чтобы типы сумм с поддержкой constexpr, такие как std::variant, были реализованы как рекурсивный союз. Было бы лучше использовать что-то вроде std::aligned_storage и размещения новых, но в настоящее время это невозможно .)

+1

«Было бы лучше использовать что-то вроде« std :: aligned_storage »и размещения нового« Я так не думаю, и учитывая, что reinterpret_cast запрещен в постоянном выражении, я не думаю, что вы можете реализовать 'std :: variant' таким образом, даже при размещении constexpr new. – cpplearner

+3

https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/_s7vi9pOhfY –

+0

@ T.C. Вы должны действительно суммировать эту дискуссию как ответ. – jotik

ответ

0
#include <cstdint> 
#include <iostream> 

class A { 
public: 
    constexpr A() = default; 
    int a = 5; 
}; 

constexpr int foo() { 
    uint8_t space[sizeof(A)]; 
    new(space) A(); 
    A& a = *reinterpret_cast<A*>(space); 
    return a.a; 
} 

int main() { 
    std::cout << foo() << std::endl; 
} 

Это, безусловно, возможно, что компилятор может понять вышеупомянутую программу. Как правило, я не думаю, что это возможно из-за сложности, необходимой для обеспечения того, чтобы параметр места размещения всегда указывал на локальную память.

Я не думаю, что понятие «память» даже относится к функциям constexpr, потому что они обычно оцениваются во время компиляции.