Search code examples
c++c++17constexprcompile-timeconstant-expression

Why references can't be used with compile time functions?


I have two snippets.

The first snippet:

#include <string>

template <typename T>
constexpr bool foo(T&&) {
    return false;
}

int main() {
    std::string a;
    if constexpr (foo(a)) {
    }
}

The second snippet:

#include <string>

template <typename T>
constexpr bool foo(T&&) {
    return false;
}

int main() {
    std::string a;
    std::string& x = a;
    if constexpr (foo(x)) {
    }
}

The first one compiles, but the second one does not compile (error message: error: the value of ‘x’ is not usable in a constant expression. Why? Why a is usable in a constant expression and x is not?

The command, used to compile g++ -std=c++17 main.cpp.


Solution

  • Because usually a constant expression cannot evaluate a reference that refers to an object with automatic storage duration. Here I mean "evaluate" by determining the identity of the object, not by determining the value of the object. So even the value of the object a is not required in your example (i.e. no lvalue-to-rvalue conversion is applied), foo(x) is still not a constant expression.

    Note foo(a) does not evaluate any reference. Although the parameter of foo is a reference, it is not evaluated as an expression. In fact, even if it was evaluated, for example,

    template <typename T>
    constexpr bool foo(T&& t) {
        t;
        return false;
    }
    

    foo(a) is still a constant expression. Such cases are exceptions as the reference t is initialized within the evaluation of foo(a).


    Related part in the standard (irrelevant part is elided by me):

    [expr.const]/2:

    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;

    • ...

    [expr.const]/6:

    A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), ... An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.