Search code examples
c++referencelanguage-lawyerc++20constexpr

When does reference evaluation make something not a constant expression?


Consider the following snippet:

struct test1 {
    static constexpr int get()  {
        return 1;
    }
};

struct test2 {
    constexpr int get() const {
        return 1;
    }
};

template <class T>
int get(T&& t) {
    if constexpr (t.get() == 1) {
        return 1;
    }
    return 2;
}

int main() {
    return get(test1{}) + get(test2{});
}

When trying to compile with GCC-11.1 (-std=c++2a), get template successfully compiles with test1, but not with test2. The only difference between them is fact that test2::get is static.

Obviously, it does not compile with test2, because t parameter is not a "core constant expression", as per 7.7 expr.const(5.13):

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...

The question is why it does compile, when the function being accessed via the very same reference is static. Isn't the refence "evaluated" in this case? Is it a GCC bug or there's some wording in the Standard that allows it?


Solution

  • Pointers and references to unknowns in constant expressions being directly ill-formed will possibly be addressed in C++23 and, if so, as a Defect Report for earlier language versions.


    [...] when the function being accessed via the very same reference is static. Isn't the refence "evaluated" in this case? Is it a GCC bug or there's some wording in the Standard that allows it?

    Your program is ill-formed also for the static case, as is answered in detail in the follow Q&A:

    However, EWG considered this a defect in the specification of constexpr, and recommending CWG to consider resolving it by P2280R3 (Using unknown pointers and references in constant expressions), targeted for C++23, and as a DR (defect report) for C++11 through C++20.

    jfbastien commented on Feb 3, 2021

    EWG saw this paper in today's telecon.

    P2280 Using unknown references in constant expressions

    The use cases presented in P2280 are problems in C++’s specification of constexpr, and we would like to fix these problems, ideally in C++23.

    This should be a Defect Report against C++20, C++17, C++14, and C++11.

    CWG agreed and P2280 has now been accepted into C++23 and as a defect report.