我遇到了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
没有产生任何警告。
两种变体都是正确的吗?如果没有,为什么不呢?该标准对此有何意见?
答案 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
中的一个变量。)