Are concepts with only a boolean literal value ill-formed, no diagnostic required?

Viewed 1021

I was playing around with C++ concepts and function overloading in a context completely removed from any templates, and stumbled upon this:

struct S
{
    int mult(int x) requires (true)  { return x; }
    int mult(int x) requires (false) { return x * 2; }
};

int main()
{
    std::cout << S{}.mult(5) << std::endl;
}

g++ 11 refuses to compile this snippet because requires-clauses may not be attached to non-template functions.

clang++ 13 is, however, fine with this snippet, but surprisingly spits out 10 instead of the 5 that I expected.

I know that the C++20 standard has only recently come out of the oven, so I completely understand that there are many issues to be worked out regarding concepts.

Disregarding the apparent uselessness of constant literal concepts, my question is: Are programs with requires-clauses which are always false ill-formed, possibly without requiring a diagnostic? Or, perhaps, is what I have not even legal C++ at all, as g++ is saying?

3 Answers

Your snippet is not legal C++.

[dcl.decl.general]

4 The optional requires-clause ([temp.pre]) in an init-declarator or member-declarator shall be present only if the declarator declares a templated function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. [...]

Since there isn't a template in sight (and no room to discuss if the mult overloads are templated functions), your attempt is plain ill-formed. It's a "shall" requirement of a diagnosable rule.

So GCC is correct. Clang is doubly wrong to call a completely unintuitive overload. Though it really went of the rails when it accepted the program to being with.

These are the two first examples in the "trailing requires-clause" section of the standard:

void f1(int a) requires true;               // error: non-templated function

template<typename T>
  auto f2(T a) -> bool requires true;       // OK

Although examples given in the standard are explicitly non-normative, these make the intent abundantly clear.

Essentially, concepts can only be applied to template functions (so your code is invalid C++), but Boolean literals (e.g., requires true) are perfectly valid.

However, templates whose requirements are never satisfied (whether by a literal false in a required clause or otherwise) seem to be ill-formed, as indicated by this example,

As n. 1.8e9-where's-my-share m.'s answer says, concepts can only be used with templates. So your example is ill-formed.

What if a requires-clause which are always false appears in a template? According to [temp.res.general]/6.1:

The program is ill-formed, no diagnostic required, if:

  • no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or ...

It is still ill-formed, but no diagnostic required. Example 11 in [temp.res.general] also confirms this.

[Example 11:

template<typename T> struct S1 {
  template<typename U>
    requires false
  struct Inner1;                // ill-formed, no diagnostic required
};

template<typename T> struct S2 {
  template<typename U>
    requires (sizeof(T[-(int)sizeof(T)]) > 1)
  struct Inner2;                // ill-formed, no diagnostic required
};

The class S1<T>​::​Inner1 is ill-formed, no diagnostic required, because it has no valid specializations. S2 is ill-formed, no diagnostic required, since no substitution into the constraints of its Inner2 template would result in a valid expression. — end example]

Related