C++17中模板参数包的偏序规则

Partial ordering rules of template parameter pack in C++17

这是来自 temp.deduct.partial 的示例。

template<class... Args>           void f(Args... args);         // #1
template<class T1, class... Args> void f(T1 a1, Args... args);  // #2
template<class T1, class T2>      void f(T1 a1, T2 a2);         // #3

f();                // calls #1
f(1, 2, 3);         // calls #2
f(1, 2);            // calls #3; non-variadic template #3 is more specialized
                    // than the variadic templates #1 and #2

为什么 f(1, 2, 3) 调用 #2

CWG1395之前很容易理解。 #2不能从#1推导出来,因为Args是参数包,而T1不是,所以#2#1更特化。

但是CWG1395之后如何理解这个例子呢?现在看来T1可以从Args推导出来

Similarly, if A was transformed from a function parameter pack, it is compared with each remaining parameter type of the parameter template.

CWG1395 似乎没有更改与您从标准中引用的示例相关的任何内容。请记住,发布 CWG1935 是为了允许例如

    template<class T>
    void print(ostream &os, const T &t) {
        os << t;
    }

    template <class T, class... Args>
    void print(ostream &os, const T &t, const Args&... rest) {
        os << t << ", ";
        print(os, rest...);
    }

    int main() {
        print(cout, 42);
        print(cout, 42, 1.23);
    }

在问题 1395 之前,调用 print(os, rest...) 的参数包扩展永远无法与 void print(ostream &os, const T &t) 的模板参数 T 匹配,因为函数参数包必须显式地匹配模板参数包:

If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails.

随着更改,第一个 print 函数现在可以与函数参数包调用匹配,并且被认为比 13.10.3.5 [temp.deduct.partial] 第 10 段中的第二个重载更专业:

If, after considering the above, function template F is at least as specialized as function template G and vice-versa, and if G has a trailing paramter pack for which F does not have a corresponding parameter, and if F does not have a trailing parameter pack, then F is more specialized than G.

您上面的示例与函数参数包无关,因此不受更改的影响,因此 [temp.deduct.type]/13.10.3.6 §10 的规则仍然适用。