Are rules for partial ordering of the template defined?

I noticed quite a few questions about templates that are related to partial ordering rules, and they all seem to be inconsistent with each other. I thought that I myself would earn the standard itself and expose it. The bear is with me.

Both gcc and clang seem to agree with the template ordering algorithm, but this algorithm is not actually displayed in the standard. In a specific order:

Consistency of the displayed values:

template <typename T> void foo(T, T); // (1) template <typename T, typename U> void foo(T, U); // (2) 

temp.deduct.type / 2 makes it clear that there should be exactly one set of output values ​​for Ps. But there is no such statement in the partial order rule. The algorithm described only compares P / A in pairs, so the synthesized call from (2) to (1) via foo(U{}, V{}) can succeed in output. Both gcc and clang agree that (1) is more specialized.

Create a synthesizer pattern template

 template <typename T> struct identity { using type = T; }; template<typename T> void bar(T, T ); // (1) template<typename T> void bar(T, typename identity<T>::type ); // (2) 

Here, if synthesized for (2) Unique2 and typename identity<Unique2>::type == Unique2 , then the output type will be successful in both directions, and the call to bar(0,0) will be ambiguous. However, it seems that both compilers instead simply consider typename identity<Unique2>::type as Unique2_b , thus the output from the template from (2) to (1) is not performed (based on the implied missing consistency rule).

Unintentional context violation

Similar to the previous example, but now define:

 template <typename T> struct identity; template <> struct identity<int> { using type = int; }; 

Without creating an instance of the template during synthesis and consistency, the output (2) ==> (1) is not executed. But if we consider the call to (1) ==> (2), we map T to Unique1 , and then the non-specific context typename identity<Unique1>::type should match Unique1 , but it will fail to replace. It seems that the approach used by gcc and clang (both of which prefer (1) here) is to ignore the argument of the indefinite context if this type of parameter is inferred from another type of template parameter that matches.

Do I make sense?

The approaches that gcc / clang make sense, but I do not think this is too clear in the standard. Can anyone check my logic?

+5
source share

All Articles