【发布时间】:2011-06-17 10:51:20
【问题描述】:
我一直在试验可变参数模板和参数转发。我想我发现了一些不一致的行为。
为了说明,这个程序:
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <cxxabi.h>
template <typename... Args> struct X {};
struct A {
A () {}
A (const A &) {
std :: cout << "copy\n";
}
};
template <typename T> const char * type_name () {
return abi :: __cxa_demangle (typeid (T) .name (), 0, 0, NULL);
}
void foo () {}
template <typename... Args>
void foo (const A &, Args ... args) {
std :: cout << type_name <X <Args...>> () << "\n“; foo (args...);
}
int main () {
foo (A(), A());
}
输出以下内容:
X<A, A>
copy
X<A>
尽管 foo 的模板特化有一个 const 引用第一个参数,但可变参数是按值传递的,因为模板类型被推断为非引用类型,正如 X<A> 输出所示。
所以,我咨询Thomas Becker:
template<typename T> void foo(T&&);这里适用以下情况:
当在 A 类型的左值上调用 foo 时,T 解析为 A& 并且 因此,通过参考折叠 上面的规则,参数类型 有效地变成了 A&。
当在 A 类型的右值上调用 foo 时,T 解析为 A,并且 因此参数类型变为 A&&。
试试这个:
template <typename... Args>
void foo (const A &, Args && ... args) {
std :: cout << type_name<X<Args...>>() << "\n";
foo (args...);
}
哪些输出:
X<A, A>
X<A&>
现在我被难住了。这里有 foo 的三个调用。在我看来,main() 应该推断出foo<A,A,A>(A&&,A&&,A&&)(因为 A() 是一个未命名的右值,因此是一个引用),它重载解析为foo<A,A,A>(const A&,A&&,A&&)。这反过来推导出foo<A,A>(A&&,A&&)等等。
问题是:为什么X<A,A> 没有引用As 而X<A&> 有引用A?
这会导致问题,因为我不能在递归中使用std::forward。
【问题讨论】:
-
您确定您的代码与您的输出相符吗?我得到
X<A> X<>,或者A()s 在main、X<A, A> copy X<A> X<>中的数量增加。你怎么能把X<A&>作为最后一行,不管有没有和号,这是一个谜。无论如何都应该是X<>。
标签: templates reference c++11 forwarding variadic