Consider the following two overloads of a function template foo
:
template <typename T> void foo(T) requires std::integral<T> { std::cout << "foo requires integral\n"; } template <typename T> int foo(T) requires std::integral<T> && true { std::cout << "foo requires integral and true\n"; return 0; }
Note the difference between the two constraints: the second has an extra && true
.
Intuitively speaking, true
is redundant in a conjunction (since X && true
is just X
). However, it looks like this makes a semantic difference, as foo(42)
would call the second overload.
Why is this the case? Specifically, why is the second function template a better overload?
As per [temp.constr.order], particularly [temp.constr.order]/1 and [temp.constr.order]/3
/1 A constraint
P
subsumes a constraintQ
if and only if, [...] [ Example: Let A and B be atomic constraints. The constraintA ∧ B
subsumesA
, butA
does not subsumeA ∧ B
. The constraintA
subsumesA ∨ B
, butA ∨ B
does not subsumeA
. Also note that every constraint subsumes itself. — end example ]/3 A declaration
D1
is at least as constrained as a declarationD2
if
- (3.1)
D1
andD2
are both constrained declarations andD1
's associated constraints subsume those ofD2
; or- (3.2) D2 has no associated constraints.
if we consider A
as std::integral<T>
and B
as true
; then:
A ∧ B
which is std::integral<T> && true
subsumes A
, which is std::integral<T>
,meaning that for the following declarations:
// Denote D1 template <typename T> void foo(T) requires std::integral<T> && true; // Denote D2 template <typename T> void foo(T) requires std::integral<T>;
the associated constraints of D1
subsume those of D2
, and thus D1
is at least as constrained as D2
. Meanwhile the reverse does not hold, and D2
is not at least as constrained as D1
. This means, as per [temp.constr.order]/4
A declaration
D1
is more constrained than another declarationD2
whenD1
is at least as constrained asD2
, andD2
is not at least as constrained asD1
.
that the declaration D1
is more constrained than declaration D2
, and D1
is subsequently chosen as the best match by overload resolution, as per [temp.func.order]/2:
Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process. If both deductions succeed, the partial ordering selects the more constrained template (if one exists) as determined below.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With