c++c++20standardsc++-conceptstype-constraints

Why is a consteval function expression NOT a primary expression?


Consider the following code snippet (compiled with clang19):

consteval bool IsEven(int n) {
    return 0 == n % 2;
}
   
template<int n>
requires (IsEven(n)) // ok
void f1() {}

template<int n>
requires IsEven(n) // error: Atomic constraint must be of type 'bool'
                   // (found '<overloaded function type>')
void f2() {}

The cppref page tells me IsEven(n) is not a primary expression. I just wonder:

Why is a consteval function expression NOT a primary expression?


Solution

  • This doesn't have anything to do with consteval. Primary expressions are simply a syntactic category of expression in the C++ grammar, and function calls aren't in that category.

    A primary expression is required to avoid parsing ambiguity. The standard gives the following example:

    template<int N> requires N == sizeof new unsigned short
    int f();
    

    If arbitrary expressions were allowed, it would be ambiguous whether the constraint is N == sizeof new unsigned short and the return type is int, or the constraint is N == sizeof new unsigned and the return type is short int.

    It's possible the grammar could have allowed some or all function call expressions without formal ambiguity, but doing so would complicate the grammar without adding meaningful expressive power - the syntax is supposed to encourage the use of named concepts, and if you really want to write a function call, you can wrap it in parentheses, as you did.