9

I'm trying to figure out whether GCC or Clang interpret the C++17 standard differently / wrong here.

This is my code, which does compile using GCC 8, but not using Clang 6:

struct BoolHolder {
    constexpr static bool b = true;
};

template<bool b>
class Foo {};

int main() {
    BoolHolder b;
    Foo<b.b> f; // Works

    BoolHolder & br = b;
    Foo<br.b> f2; // Doesn't work
}

I wonder why that is. Obviously, b.b is a valid constexpr (or the first Foo<b.b> wouldn't be valid). Is br.b not a valid constexpr? Why? The object or the reference itself should have nothing to do with it, since we're accessing a static constexpr member here, right?

If this is really not valid C++17, should the fact that GCC doesn't even warn me (even though I enabled -Wall -Wextra -pedantic) be considered a bug?

3
  • FWIW, MSVS and icc also compile. Commented Aug 6, 2018 at 14:54
  • I think this is related to the question: with constexpr int f(int) { return 0;}, would f(x) be a constexpr for int x;? stackoverflow.com/questions/47696686/… Commented Aug 6, 2018 at 15:00
  • I would not bet that the reference is not relevant here. bris not constexpr and so everything based on br is also not constexpr. Maybe as workaround you could use BoolHolder::b, if BoolHolder is not constant within this context you might use decltype. Commented Aug 6, 2018 at 15:03

1 Answer 1

10

Clang is correct. References are evaluated "eagerly" in constant expressions, so to speak. [expr.const]/2.11:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • [...]
  • an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
    • it is initialized with a constant expression or
    • its lifetime began within the evaluation of e;
  • [...]
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, but shouldn't the … unless […] it is initialized with a constant expression … part be true here? Also, should the expression br.b really evaluate to an id-expression? It's a static member access, thus the object itself is irrelevant?
b is not a constant expression. The object expression is still evaluated even though the result is discarded.
Sad that it is not interpreted as BoolHolder::b first.
@Jarod42 Would you prefer f().x to not evaluate f() if x is a static data member?
What does "unless the reference has a preceding initialization" mean?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.