Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In concept definitions, are substitution failures allowed outside of a requires expression?

Consider this code:

#include <type_traits>                                           
#include <iostream>

template <class T> concept bool C1 = std::is_same<T, int>::value; 

template <class T> concept bool C2 =  
    C1<decltype(std::declval<T>() + std::declval<T>())>; 

struct A {};                   

int main() { 
  std::cout << C2<int>; 
  std::cout << C2<A>;                                                 
  return 0;                                                           
}

GCC compiles it fine and prints 10.

But §14.10.1.2 Predicate constraints [temp.constr.pred] of N4553 says

A predicate constraint is a constraint that evaluates a constant expression E (5.19).

and then

After substitution, E shall have type bool.

Since C1<decltype(std::declval<A>() + std::declval<A>())> is a substitution failure, rather than having type bool, does that mean the program should be ill-formed?

like image 294
Ryan Burn Avatar asked Dec 05 '15 17:12

Ryan Burn


People also ask

Why do you need the requires clause?

Its purpose is to determine if one or more expressions are well-formed. It has no side effects and does not affect the behavior of the program. A requires clause uses a compile-time Boolean expression to define requirements on template arguments or function declarations.

What are concepts CPP?

The main uses of concepts are: introducing type-checking to template programming. simplified compiler diagnostics for failed template instantiations. selecting function template overloads and class template specializations based on type properties. constraining automatic type deduction.

What are CPP constraints?

A constraint is a requirement that types used as type arguments must satisfy. For example, a constraint might be that the type argument must implement a certain interface or inherit from a specific class. Constraints are optional; not specifying a constraint on a parameter is equivalent to using a Object constraint.

How do you define a function template?

Defining a Function TemplateA function template starts with the keyword template followed by template parameter(s) inside <> which is followed by the function definition. In the above code, T is a template argument that accepts different data types ( int , float , etc.), and typename is a keyword.


1 Answers

The Concepts TS only defines behavior for determining the satisfaction of the associated constraints of a declaration; there's no provision for referring to a concept name outside of associated constraints. So strictly speaking, std::cout << C<int> and std::cout << C<A> are both ill-formed.

EWG decided in Kona to allow this as a new feature:

Straw poll: SF | F | N | A | SA

  • Should we allow evaluation of concepts anywhere? 8 | 6 | 2 | 0 | 0
  • Should we allow the presence and evaluation of a requires-expression in any expression? 1 | 2 | 10 | 3 | 1
    • Note that without the first poll, the second poll would change.

but there is no wording yet to specify its behavior.

GCC currently allows concepts-as-expressions as an (I believe undocumented) extension. I find it quite likely that this feature will be specified so that C<X...> evaluates to false when substitution of X... into the initializer of C fails to produce a valid expression, and otherwise has the value of the expression so obtained. That seems like the sane way to do this, and is consistent with the implementation in GCC.

like image 66
Casey Avatar answered Oct 19 '22 03:10

Casey