consteval функция, возвращающая объект с нетривиальным деструктором constexpr

C ++ 20 будет иметь новый consteval ключевое слово и деструктор constexpr Если все будет хорошо. К сожалению, ни один из известных мне компиляторов не реализует consteval в это время. Будет ли действителен следующий код?

struct A {
  constexpr ~A() {}
};

consteval A f() {
    return A{};
}

void test() {
    A a;
    a = f(); // <-- here
}

Проблема возникает из отмеченной мною строки - необходимо вызвать деструктор временного A, возвращаемого f. но его следует вызывать в конце полного выражения. так что вне непосредственной оценки.

Я не нашел цитат из consteval и деструктор constexpr документы, которые прямо запрещают это, но я не понимаю, как это может быть правильно.

Будет ли следующий код действителен в C ++ 20? Что должно произойти с этим кодом?


Примечание:

В consteval paper это приведен пример. Здесь функция consteval вызывается вне постоянного контекста.

consteval int sqr(int n) {
  return n*n;
}
constexpr int r = sqr(100);  // Okay.
int x = 100;
int r2 = sqr(x);  // Error: Call does not produce a constant.

person Tyker    schedule 14.10.2019    source источник
comment
из моего понимания consteval это не тот случай, когда вызов будет свернут во время выполнения. но присвоение константе a константы f будет назначено во время выполнения.   -  person Tyker    schedule 14.10.2019
comment
Что касается редактирования с помощью, здесь функция consteval вызывается вне постоянного контекста., почему вы думаете, что она не считается постоянным контекстом? Кроме того, вы видели constexpr int dblsqr(int n) { return 2*sqr(n); // Error: Enclosing function is not } // consteval. часть?   -  person NathanOliver    schedule 14.10.2019
comment
Я думаю, что проблема с constexpr int dblsqr(int n) { return 2*sqr(n); // Error: Enclosing function is not } // consteval. заключается в том, что аргумент, передаваемый функции consteval, неизвестен во время компиляции или, возможно, не известен.   -  person Tyker    schedule 14.10.2019
comment
Точно. Это не постоянное выражение, поэтому его нельзя вызвать.   -  person NathanOliver    schedule 14.10.2019
comment
аргумент, не являющийся постоянным выражением, и вызов, находящийся вне постоянного контекста, - это две разные вещи.   -  person Tyker    schedule 14.10.2019
comment
Do'h. Это правильно. Мое мышление перевернулось.   -  person NathanOliver    schedule 14.10.2019


Ответы (1)


Я думаю, что с этим кодом все в порядке.

Важным аспектом consteval является [expr.const] / 12:

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

In

void test() {
    A a;
    a = f(); // <-- here
}

f() - это немедленный вызов (это явный вызов немедленной функции, которая не находится в контексте немедленной функции). Таким образом, требуется, чтобы f() было постоянным выражением.

Примечание: просто f(), а не a = f();, здесь не требуется, чтобы оператор присваивания был постоянным выражением.

Все, что вызывает f(), прекрасно. Все специальные функции-члены A вызываются в течение постоянного времени оценки. Результат f() является допустимым результатом постоянного выражения ([expr.const] / 10) аналогично, потому что он также не вызывает никаких ограничений (A не имеет указателей или ссылочных элементов, поэтому тривиально ни один из них не относится к объектам без статической продолжительности хранения).

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

person Barry    schedule 14.10.2019
comment
поэтому деструктор значения, возвращаемого f, не будет вызываться или вызываться во время выполнения для константы, вычисляемой во время выполнения? - person Tyker; 14.10.2019
comment
@Tyker Да, он будет вызываться во время выполнения. Временное материализуется, а затем его нужно уничтожить. - person Barry; 14.10.2019
comment
Ладно, странно, но ладно. - person Tyker; 14.10.2019
comment
немедленный вызов - это полное выражение и все побочные эффекты полного выражения устраняются во время полного выражения, так как можно деструктор значения возвращенный f быть выполнен вне непосредственного вызова? - person Tyker; 15.10.2019
comment
@Tyker Мы должны вызвать A::operator=() во время выполнения, назначая его из объекта, который еще не должен быть уничтожен. - person Barry; 15.10.2019
comment
Материализация временного и его последующее разрушение не являются частью немедленного обращения. - person T.C.; 15.10.2019
comment
Я понимаю, что мы не можем уничтожить объект, пока он нам еще нужен. но уничтожение объекта после присвоения означает, что побочный эффект (уничтожение возвращаемого значения) полного выражения (немедленные вызовы являются полным выражением) вычисляется после конца полного выражения. которые кажутся противоречащими eel.is/c++draft/intro.execution#9 < / а> - person Tyker; 15.10.2019
comment
@TC, поэтому разрушение временных конструкций не считается побочным эффектом, пока временное не материализуется? - person Tyker; 15.10.2019