constexpr и изменяемый член и неявный copy-ctor - PullRequest
4 голосов
/ 10 января 2020

Следующий код компилируется в clang 7+, но не в 5 & 6 (с c ++ 17 и c ++ 14). Проблема для clang 5 и 6, по-видимому, заключается в том, что неявное копирование ctor читает с изменяемого члена x.

Кто-нибудь может сказать мне, если вся конструкция соответствует стандарту (c ++ 17), или если программа плохо сформирована? Или произошло изменение в стандарте, касающемся неявного copy-ctor, который не мог быть реализован в более ранних версиях clang?

struct Foo {

    int a;
    mutable int x{};

    constexpr Foo() : a(0) {}

    //constexpr Foo(const Foo& other) : a(other.a) {} // <- with this line it works on Clang 5 & 6, too
};

struct FooFactory {

    static constexpr auto create() {
        auto f = Foo{};       
        return f;
    }
};

int main() {

    constexpr Foo f = FooFactory::create();
    ++f.x;
}

Живой код здесь .

Ответы [ 2 ]

4 голосов
/ 10 января 2020

Это правильно сформированная программа на C ++ 17. Функция constexpr, конечно, может читать (и записывать) непостоянные переменные:

constexpr int f(int i) {
  int j=i;
  ++j;
  return i+j;  // neither is a constant expression
}

Правило состоит в том, что все, что проверяется в константном выражении, должно быть либо константа или начала жизни во время вычисления выражения. В вашем случае время жизни create f.x явно начинается в оценке константного выражения, которое является инициализация из main '* f. Однако верно, что ни один объект Foo не может быть скопирован с помощью константного выражения, которое также не создает этот объект, независимо от того, является ли он constexpr.

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

0 голосов
/ 10 января 2020

Код плохо сформирован. Для справки приведен упрощенный код, который не работает на всех компиляторах:

struct Foo {
    int a;
    mutable int x{};
    constexpr Foo() : a(0) {}

};

int main() {
    constexpr Foo f;
    constexpr Foo f1 = f;
}

Согласно [expr.const] 7.7,

Переменная может использоваться в константных выражениях после его инициализирующее объявление встречается, если это переменная constexpr,

или ... (3.5) неизменяемый подобъект или ссылочный член любого из вышеперечисленных.

Это дисквалифицирует конструкторы копирования по умолчанию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...