参数包

时间:2016-12-24 10:09:47

标签: c++ c++11 templates reference variadic-templates

请考虑以下两个重载:

template<typename T, typename ...Args>
void f(std::vector<T>&& v, Args&& ...args)
{
    std::cout << "f taking a vector + parameter pack\n";
}

template<typename ...Args>
void f(Args&& ...args)
{
    std::cout << "f taking a parameter pack\n";
}

现在,对于以下片段,选择了预期的重载:

std::vector<int> v{1, 2, 3};
f(std::move(v), 3.0);

(输出: f采用向量+参数包

对于以下情况,选择第二个重载:

std::vector<int> v{1, 2, 3};
f(v, 3.0);

(输出: f参加参数包

通用引用向量参数也绑定到左值引用,那么为什么在这种情况下仅使用参数包的重载是有利的呢? 更新:查看接受的答案,假设vector参数是通用/转发引用是错误的。

2 个答案:

答案 0 :(得分:7)

  

通用参考向量参数也绑定到左值参考

不,它不是universal reference

  

4)如果 P 是对cv-nonqualified模板参数的右值引用(所谓的&#34;转发引用&#34;),并且相应的函数调用参数是左值,使用 A 的类型左值引用代替 A 进行扣除(注意:这是std::forward操作的基础注意:在{{3 ,类模板的模板参数永远不是转发引用(因为C ++ 17)):

所以

template<typename T, typename ...Args>
void f(std::vector<T>&& v, Args&& ...args)

请注意,v不是模板参数T的右值参考,而是std::vector<T>。所以v是&#34;只是&#34;一个右值参考,然后不能绑定到左值。

答案 1 :(得分:2)

正如接受的答案所解释的那样:

  

该向量不被视为转发参考(又名通用参考)。

(编译器知道它是一个向量,因此这部分没有模板参考推论,这意味着双符号 - &amp;&amp; - 被视为对向量的右值引用未知类型T)。

但是,如果我们确实希望将矢量视为转发参考?

如果您希望将矢量作为转发参考传递,您可以执行以下操作:

template<typename T> struct is_vector : public std::false_type {};

template<typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type {};

// [1] the special case
// the vector becomes now just V and acts as Forwarding Reference
// the enable_if ensures that we deal with V that is a vector
template<typename V, typename ...Args>
typename std::enable_if<
    is_vector<std::remove_const_t<std::remove_reference_t<V>>>::value
>::type
f(V&& v, Args&& ...args) {
    std::cout << "f taking a vector + parameter pack\n";
}

// [2] the generic case
template<typename ...Args>
void f(Args&& ...args) {
    std::cout << "f taking a parameter pack\n";
}

int main() {
    // all cases below go to the 1st overload
    std::vector<int> v1{1, 2, 3};
    f(v1, 3);

    const std::vector<int> v2{1, 2, 3};
    f(v2, 3);

    f(std::vector<int>{1, 2, 3}, 3);

    // this goes to the 2nd overload
    std::array<int, 3> a{1, 2, 3};
    f(a, 3);
}