Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could non-static member variable be modified in constexpr constructor (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
  • Online Compiler URL: http://goo.gl/jni6Em
  • Compiler: clang 3.4 (with -std=c++1y)
  • System: Linux 3.2

If I delete L2, this code compiles. If I add L2, the compiler complained "modification of object of const-qualified type 'const int' is not allowed in a constant expression". I am not a language lawyer, so I am not sure whether this is true. However, if it is, why compiler didn't complain anything about L1, since it also called A() as constexpr? Is this a bug of clang? Or did I miss anything?

Reference: http://en.cppreference.com/w/cpp/language/constexpr

BTW, if I change "constexpr A a;" to "A a;" (remove constexpr keyword), L1 failed to compile which is expect. However, the compiler didn't complain about L2 anymore.

Online Compiler URL about this: http://goo.gl/AoTzYx

like image 350
ytj Avatar asked May 14 '14 06:05

ytj


1 Answers

I believe this is just a case of compilers not having caught up to the changes proposed for C++14. Your constexpr constructor satisfies all the conditions listed in §7.1.5/4 of N3936. Both gcc and clang fail to compile your code, but for different reasons.

clang complains:

note: modification of object of const-qualified type 'const int' is not allowed in a constant expression

which doesn't make much sense, but reminds me of the C++11 restriction that constexpr member functions are implicitly const (this is a constructor, and that doesn't apply, but the error message is reminiscent of that). This restriction was also lifted for C++14.

gcc's error message is:

error: constexpr constructor does not have empty body

Seems pretty clear that gcc still implements the C++11 rules for constexpr constructors.

Moreover, N3597 lists this example:

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 was superseded by N3652, which contains the wording found in the current draft. Unfortunately, the earlier example disappears, but, again, nothing in the current wording says you cannot assign values to data members within the body of a constexpr constructor.

Update (2017-10-03)

clang fixed this, but there has been no new release yet: https://bugs.llvm.org/show_bug.cgi?id=19741 (Compiler explorer)

like image 187
Praetorian Avatar answered Sep 23 '22 22:09

Praetorian