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

Plu*_*uto 7 c++ templates language-lawyer 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
Run Code Online (Sandbox Code Playgroud)

为什么f(1, 2, 3)叫#2?

在CWG1395之前很容易理解。#2不能推导出,#1因为Args是一个参数包而T1不是,所以#2比 更专业#1。

但是在CWG1395之后如何理解这个例子呢?似乎T1可以从Args现在开始推断。

类似地,如果A是从函数参数包转换而来,则将其与参数模板的每个剩余参数类型进行比较。

Jod*_*cus 3

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

\n
    template<class T>\n    void print(ostream &os, const T &t) {\n        os << t;\n    }\n\n    template <class T, class... Args>\n    void print(ostream &os, const T &t, const Args&... rest) {\n        os << t << ", ";\n        print(os, rest...);\n    }\n\n    int main() {\n        print(cout, 42);\n        print(cout, 42, 1.23);\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
\n

如果 A 是从函数参数包转换而来并且 P 不是参数包,则类型推导失败。

\n
\n

随着变化,首先print现在允许第一个函数与函数参数包调用进行匹配,并被认为比 13.10.3.5 [temp.deduct.partial] 第 10 段中的第二个重载更专业:

\n
\n

考虑上述因素后,如果函数模板 F 至少与函数模板 G 一样专用,反之亦然,并且如果 G 具有尾随参数包,而 F 没有相应的参数,并且如果 F 没有尾随参数包参数包,那么F比G更专业。

\n
\n

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

\n