std :: forward <args>或std :: forward <args ...>?</args ...> </args>

时间:2014-12-17 14:54:41

标签: c++11 variadic-templates

我遇到了std::forward使用变量模板参数的两种变体。

template <typename... Args>
void foo(Args&&... arga)
{
    bar(std::forward<Args>(args)...);      // variant 1
    bar(std::forward<Args...>(args)...);   // variant 2

    // EDIT the above is a fixed version, the initial incorrect version was
    // bar(std::forward<Args>(args...));      // variant 1
    // bar(std::forward<Args...>(args...));   // variant 2

}

我尝试过使用g ++和clang两种变体,两者似乎同样有效。 -Wall -Wextra -Wpedantic没有产生任何警告。

两种变体都是正确的吗?如果没有,为什么不呢?该标准对此有何意见?

1 个答案:

答案 0 :(得分:13)

bar(std::forward<Args>(args)...);      // variant 1

这是正确的。

bar(std::forward<Args...>(args...));   // variant 2

这是错误的。

如果参数包为空,则变体1扩展为有效的bar(),但变体2扩展为bar(std::forward<>()),其格式不正确,因为forward缺少其参数。

如果包有一个元素,则两个变体都会扩展为bar(std::forward<T>(t)),这是有效的。

如果包有两个元素,则变体1正确扩展为bar(std::forward<T1>(t1), std::forward<T2>(t2)),这是有效的。但是对于两个元素,变体2扩展为bar(std::forward<T1, T2>(t1, t2)),这是不正确的,因为std::forward有一个模板参数和一个函数参数。

因此,在所有情况下,变体1都有效,但变体2仅对具有一个元素的参数包的情况有效(如果您只关心单个模板参数,则根本不应使用可变参数模板! )

基本上,包扩展应为PATTERN...,其中模式是您希望为包中的每个元素重复的内容。由于您要为每个元素调用std::forward<T>(t),因此PATTERN应为std::forward<Args>(args),因此完整包扩展后跟...(而不是... < em> inside PATTERN,导致两个单独的包扩展,Args中的一个类型和args中的一个变量。)