Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does "&& true" added to a constraint make a function template a better overload?

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?

like image 382
ph3rin Avatar asked Apr 08 '21 14:04

ph3rin


1 Answers

As per [temp.constr.order], particularly [temp.constr.order]/1 and [temp.constr.order]/3

/1 A constraint P subsumes a constraint Q if and only if, [...] [ Example: Let A and B be atomic constraints. The constraint A ∧ B subsumes A, but A does not subsume A ∧ B. The constraint A subsumes A ∨ B, but A ∨ B does not subsume A. Also note that every constraint subsumes itself. — end example ]

/3 A declaration D1 is at least as constrained as a declaration D2 if

  • (3.1) D1 and D2 are both constrained declarations and D1's associated constraints subsume those of D2; 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 declaration D2 when D1 is at least as constrained as D2, and D2 is not at least as constrained as D1.

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.

like image 141
dfrib Avatar answered Sep 22 '22 05:09

dfrib