Можно ли изменить нестатическую переменную-член в конструкторе constexpr (C ++ 14)?

struct A {
    int a = 0;
    constexpr A() { a = 1; }
};

constexpr bool f() {
    constexpr A a;
    static_assert(a.a == 1, ""); // L1: OK
    return a.a == 1;
}
static_assert(f(), ""); // L2: Error, can not modify A::a in constexpr
  • URL-адрес онлайн-компилятора: http://goo.gl/jni6Em
  • Компилятор: clang 3.4 (с -std = c ++ 1y)
  • Система: Linux 3.2

Если я удалю L2, этот код компилируется. Если я добавляю L2, компилятор жаловался, что «в постоянном выражении не допускается модификация объекта константного типа 'const int'». Я не языковой юрист, поэтому не уверен, что это правда. Однако, если это так, почему компилятор ничего не жаловался на L1, поскольку он также вызывал A () как constexpr? Это баг лязга? Или я что-то пропустил?

Ссылка: http://en.cppreference.com/w/cpp/language/constexpr

Кстати, если я изменю "constexpr A a;" к "A a;" (удалить ключевое слово constexpr), L1 не удалось скомпилировать, что ожидалось. Однако компилятор больше не жаловался на L2.

URL-адрес онлайн-компилятора об этом: http://goo.gl/AoTzYx


person ytj    schedule 14.05.2014    source источник


Ответы (1)


Я считаю, что это просто случай, когда компиляторы не догнали изменения, предложенные для C ++ 14. Ваш constexpr конструктор удовлетворяет всем условиям, перечисленным в §7.1.5 / 4 N3936. Оба gcc и clang не могут скомпилировать ваш код, но по разным причинам.

clang жалуется:

примечание: модификация объекта константного типа 'const int' не допускается в константном выражении

что не имеет особого смысла, но напоминает мне об ограничении C ++ 11, согласно которому constexpr функции-члены неявно const (это конструктор, и это не применяется, но сообщение об ошибке напоминает об этом). Это ограничение снято и для C ++ 14.

Сообщение об ошибке gcc:

ошибка: конструктор constexpr не имеет пустого тела

Кажется довольно очевидным, что gcc по-прежнему реализует правила C ++ 11 для constexpr конструкторов.

Более того, N3597 перечисляет этот пример :

struct override_raii {
  constexpr override_raii(int &a, int v) : a(a), old(a) {
    a = v;
  }
  constexpr ~override_raii() {
    a = old;
  }
  int &a, old;
};

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

Обновление (2017-10-03)

clang исправил это, но новой версии еще не было: https://bugs.llvm.org/show_bug.cgi?id=19741 (Обозреватель компилятора)

person Praetorian    schedule 14.05.2014
comment
поможет ли назначить A :: a с использованием синтаксиса инициализатора вместо тела функции конструктора? - person NHDaly; 14.05.2014
comment
@NHDaly Да, конечно. clang успешно компилирует код в этом случае. gcc по-прежнему не работает, потому что f() не удовлетворяет требованиям C ++ 11 для constexpr функций. Проблема здесь в назначении элемента данных в теле конструктора. - person Praetorian; 14.05.2014
comment
И это только потому, что gcc еще не догнал C ++ 14, да? - person NHDaly; 14.05.2014
comment
@NHDaly Казалось бы, да, по крайней мере, когда дело касается расслабленности constexpr - person Praetorian; 14.05.2014
comment
О, моя ошибка. Теперь я понимаю, что вопрос OP - это именно то, что вы описали: можем ли мы изменить неконстантную нестатическую переменную-член в конструкторе constexpr. Я на борту! - person NHDaly; 14.05.2014
comment
Я не понимаю, как этот пример применим ... Он не присваивает значение члену данных в теле конструктора, потому что a - это ссылка, не так ли? - person ildjarn; 23.05.2014
comment
@ildjarn О, черт, я совершенно упустил из виду, что и аргумент, и член данных называются a. Вы правы насчет примера, но я думаю, что в целом ответ правильный, потому что Ричард Смит прокомментировал отчет об ошибке, подтверждающий, что это действительно ошибка. - person Praetorian; 23.05.2014
comment
О, я не имел в виду, что не согласен с ответом, я просто имел в виду применимость примера кода. : -] - person ildjarn; 23.05.2014