【问题标题】:variadic list vs single template parameter: what does the standard say?可变参数列表与单个模板参数:标准怎么说?
【发布时间】:2012-12-20 06:01:15
【问题描述】:

考虑以下代码:

#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 标准是否说具有固定数量参数的模板函数优于具有相同签名的可变参数函数?

【问题讨论】:

    标签: c++ c++11 variadic-templates standards-compliance overload-resolution


    【解决方案1】:

    It is reallyquite simple(两个活生生的例子,gcc 和 clang)

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

    Overloads not taking ... seem to be preferred when the choice is an explicit template parameter.

    class=std::enable_if_t 不会改变这一点。

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

    14.8.2.4 在部分排序期间推导模板参数 [temp.deduct.partial]

    /8:

    如果A 是从函数参数包转换而来的,而P 不是参数包,则类型推导失败。否则,使用生成的类型PA,然后按照14.8.2.5 中的描述进行推导。如果P是函数参数包,则参数模板的每个剩余参数类型的类型A与declarator-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) 示例。

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

    【讨论】:

      【解决方案2】:

      由于在“单一”版本中使用了第二个模板参数 enable_if,编译器认为该版本是一个更专业的模板,可用于启用它的类型。
      它被认为更专业,因为有些类型可以实例化可变参数模板,但“单个”不能。

      一般规则是,更专业的模板在重载决议中胜过不专业的模板。

      【讨论】:

      • 注意:enable_if 与“Single”重载无关,它更专业,它是正交的,用于从可能的重载集合中删除函数。
      • 但是当它不删除函数时,你会得到f&lt;int, void&gt;(const int&amp;),它比f&lt;int&gt;(const int&amp;)更专业。第二个模板参数是enable_if 的事实不相关。但它具有第二个参数的事实是相关的,并且是选择重载的原因。将 enable_if 类型替换为 void 使得 f(std::string()) 的重载可行,然后它也被选择用于更专业的调用。
      • @MatthieuM。我同意这是使用enable_if 的意图。正如 Jonathan 解释的那样,它的副作用是使模板更专门用于那些没有被删除的情况。
      • @JonathanWakely:哎呀,你说得对,我在这里有点草率。
      • @JonathanWakely 我错过了什么吗?您不需要第二个类型参数来使单个参数在重载决议中胜出。
      猜你喜欢
      • 2012-08-07
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 1970-01-01
      • 2014-04-21
      • 2019-11-22
      相关资源
      最近更新 更多