Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can requires-expression in C++20 be of type implicitly convertible to bool?

In the following example the requires-expression of second f-function overload has the type std::integral_constant<bool,true>, which is implicitly convertible to bool:

#include <type_traits>

struct S {
    static constexpr bool valid = true;
};

template<typename T>
int f() { return 1; }
template<typename T>
int f() requires( std::bool_constant< T::valid >() ) { return 2; }

int main() {
    return f<S>();
}

One can observe that GCC rejects the program due to the type is not precisely bool, but Clang accepts, but selects the other overload int f() { return 1; }. Demo: https://gcc.godbolt.org/z/nf65zrxoK

Which compiler is correct here?

like image 350
Fedor Avatar asked Oct 02 '21 08:10

Fedor


People also ask

What is a requires expression in C++?

Requires expressions The keyword requires is also used to begin a requires-expression, which is a prvalue expression of type bool that describes the constraints on some template arguments. Such an expression is true if the constraints are satisfied, and false otherwise:

What is the implicit type conversion in C?

Check out our Data Structures in C course to start learning today. There are many ways in which the Implicit Type Conversion occurs in C, such as: A rank can be assigned to the integer and floating-point arithmetic type, from 1 to 9.

Is it possible to have a requires clause with a bool?

This example is perhaps a little bit silly, since we just replicate the expression in the return statement, but its purpose is to demonstrate the syntax for requires clauses. However, not every expression of the type bool is allowed in a requires clause. Here is an example that does not work:

What is simple requirement in C++?

A simple requirement is an arbitrary expression statement that does not start with the keyword requires. It asserts that the expression is valid. The expression is an unevaluated operand; only language correctness is checked. A requirement that starts with the keyword requires is always interpreted as a nested requirement.


Video Answer


1 Answers

I believe GCC is correct—the type must be bool exactly per [temp.constr.atomic]/3 (note that E here is std::bool_constant< T::valid >()):

To determine if an atomic constraint is satisfied, the parameter mapping and template arguments are first substituted into its expression. If substitution results in an invalid type or expression, the constraint is not satisfied. Otherwise, the lvalue-to-rvalue conversion is performed if necessary, and E shall be a constant expression of type bool. The constraint is satisfied if and only if evaluation of E results in true. If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required. [ Example:

template<typename T> concept C =
  sizeof(T) == 4 && !true;      // requires atomic constraints sizeof(T) == 4 and !true

template<typename T> struct S {
  constexpr operator bool() const { return true; }
};

template<typename T> requires (S<T>{})
void f(T);                      // #1
void f(int);                    // #2

void g() {
  f(0);                         // error: expression S<int>{} does not have type bool
}                               // while checking satisfaction of deduced arguments of #1;
                                // call is ill-formed even though #2 is a better match

— end example ]

like image 111
chris Avatar answered Oct 10 '22 21:10

chris