可变参数列表vs单一模板参数:标准怎么说?

variadic list vs single template parameter: what does the standard say?

本文关键字:参数 标准 怎么说 单一模 变参 列表 vs      更新时间:2023-10-16

考虑以下代码:

#include <iostream>
#include <type_traits>
// Variadic version
template<class... Variadic>
void f(const Variadic&... variadic)
{
    std::cout<<"variadic"<<std::endl;
}
// Single version
template<class Single, class = typename std::enable_if<std::is_fundamental<Single>::value>::type>
void f(const Single& single)
{
    std::cout<<"single"<<std::endl;
}
// Main
int main()
{
    f();              // variadic
    f(42);            // single : why?
    f(std::string()); // variadic 
    f(42, 42);        // variadic
    return 0;
}

我不明白为什么标记为"single"的行编译得很好(在g++ 4.6.3下)并且没有产生重载解析问题。c++11标准是否规定具有固定数量形参的模板函数优于具有相同签名的可变函数?

这真的很简单(两个实例,gcc和clang)

template<class...T> void foo(T&&...) {std::cout << "...Tn";}
template<class T> void foo(T&&) {std::cout << "Tn";}
int main() {
  foo(3);
}

当选择显式模板参数时,不使用...的重载似乎更受欢迎。

class=std::enable_if_t不改变这个

所以你的两个函数f都是候选函数,那么编译器更喜欢没有变量的函数。

14.8.2.4在部分排序时推导模板参数[temp.演绎.partial]

/8:

如果A是从函数参数包转换而P不是参数包,则类型推导失败。否则,使用结果类型PA,然后按照14.8.2.5的描述进行演绎。如果P是一个函数形参包,则实参模板的每个剩余形参类型的A类型将与声明器id的P类型进行比较函数参数包的。每次比较都会推导出由函数形参包展开的模板形参包中后续位置的模板实参。如果对给定类型的演绎成功,则认为实参模板中的类型至少与形参模板中的类型具有同样的专门化。[例子:

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 #

特别是f(1,2)的例子。

所有enable_if_t子句所做的就是当您将std::string作为T传递时,从考虑中删除单参数版本。

由于在'single'版本中使用了第二个模板参数enable_if,编译器认为该版本是一个更专门化的模板,可以与它所启用的类型一起使用。
它被认为是更专门化的,因为在某些类型中可变模板可以被实例化,但'single'不能。

一般规则是,在重载解析方面,专门化程度高的模板优于专门化程度低的模板。