Home > Software engineering >  What is the rationale to disallow type traits in type-constraints in addition to concepts?
What is the rationale to disallow type traits in type-constraints in addition to concepts?

Time:12-23

The language specification, when introducing Concepts, implicitly disallows type traits to be used in type-constraint contexts in lieu of concepts:

#include <type_traits>

// doesn't work because std::is_arithmetic_v is not a type
template <std::is_arithmetic_v T> struct A{};

// legal, but doesn't restrict T, but expects an object of type std:: is_arithmetic
template <std::is_arithmetic T> struct B{};

I vaguely remember that during the specification process, people where unable to get the concept of Concepts to work without introducing a new concept keyword and the corresponding mechanism for defining a Concept.

However, in the definition of A, the construct template <bool-expression ID> was never legal, so allowing it would not have clashed with other language constructs.

So, what stands in the way of directly allowing such constructs instead of having to introduce a lot of wrapper-Concepts for already existing std type traits — not to mention custom type traits?


Note: It is clear that writing a generic concept template to wrap existing type traits is trivial. It is not the question how to reuse old traits, but why the language didn't opt to allow it in the first place? Perhaps even instead of introducing a new keyword.

CodePudding user response:

The ordinary evaluation semantics of type traits denies defining any meaningful relationships among them; lacking that subsumption would prevent many productive uses of constrained declarations. For example:

template<nonstd::is_semiregular_v T> void f(T);
template<nonstd::is_regular_v T> void f(T);
void g(int i) {
  f(i);  // error: ambiguous
}

The corresponding code with concepts selects the overload with the stronger concept (which might have better semantics or be more efficient).

CodePudding user response:

The very first paper defining what would eventually become the C 20 concepts feature was N3580 (PDF) from early 2013.

In N3580, constraints are defined to be any constexpr template function that takes no function parameters and returns a bool. However, the concept keyword does exist and does have a justification for existing. In particular, the keyword is what opens up the use of constraints in specialized syntactic constructs. Section 6.2.3 lays out the reasoning:

It seems that we need two names for every concept: one for the concept/constraint itself plus one for its constrained parameter name. [...] Our solution is that the name of a constraint doubles as the name of its constrained parameter. This then implies that a constraint that is to be used for the terse syntax must be syntactically distinguished. In other words, it must be defined to be a concept using a special syntax or a keyword. We use concept.

This is stated within a section discussing terse syntax for constraining templates. Things like template<ConceptName T>.

So it is clear that the very genesis of concept as a keyword was to allow for using concept names in specialized syntax.

Obviously the concepts functionality evolved substantially over time. In particular, the dual-name issue became irrelevant as using a concept-name to represent the typename deduced from it disappeared entirely. But in every version of "concepts-lite", the keyword concept represented the separation between "a boolean expression I can use in a constraint" and "a special entity that can be used in particular grammar".

  • Related