请考虑以下计划:
#include <iostream>
template <typename T, typename ...Ts>
struct Foo {
template <typename ...Us>
static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1, Us... args) {
std::cout << " -> Foo<...>::bar() enter [ " << oT0 << ", " << oT1 << " ]" << std::endl;
Foo<T>::bar(oT0, oT1, iT0, iT1);
Foo<Ts...>::bar(args...);
std::cout << " <- Foo<...>::bar() exit [ " << oT0 << ", " << oT1 << " ]" << std::endl;
}
};
template <typename T>
struct Foo<T> {
static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1) {
std::cout << " -> Foo<>::bar() enter [ " << oT0 << ", " << oT1 << " ]" << std::endl;
oT0 = iT0;
oT1 = iT1;
std::cout << " <- Foo<>::bar() exit [ " << oT0 << ", " << oT1 << " ]" << std::endl;
}
};
int main() {
int i0 = -1,
i1 = 0;
float f0 = -97.18f,
f1 = 3.141592f;
std::cout << "( "<< i0 << ", " << i1 << "; " << f0 << ", " << f1 << " ) " << std::endl;
Foo<int, float, int>::bar(i0, i1, 0, 1, f0, f1, 18.f, -7.f, i0, i1, 4, 17);
std::cout << "( "<< i0 << ", " << i1 << "; " << f0 << ", " << f1 << " ) " << std::endl;
Foo<float>::bar(f0, f1, 18.f, -7.f);
std::cout << "( " << f0 << ", " << f1 << " ) " << std::endl;
Foo<float, int>::bar(f0, f1, 2.71f, 9000.1f, i0, i1, 4, 17);
std::cout << "( "<< i0 << ", " << i1 << "; " << f0 << ", " << f1 << " ) " << std::endl;
return 0;
}
其注释输出(为清晰起见而删除了调试输出,但在IDEone处可用):
( -1, 0; -97.18, 3.14159 ) // initial values
( 0, 1; -97.18, 3.14159 ) // ints only set once?! floats unchanged?!
( 18, -7 )
( 0, 1; 2.71, 9000.1 ) // ints unchanged?!
我必须遗漏一些明显的东西:从上面开始,调用Foo<...>::bar(...)
只修改第一组两个非const参数。为什么下一个参数的值不会在main
中保持不变?
答案 0 :(得分:4)
您需要在模板的varargs部分使用引用,否则前四个之外的参数将按值传递给初始调用(复制到局部变量)。后续调用将改变那些复制的值,而不是传递的原始参数。
由于您希望接受某些参数的rvalues,use perfect forwarding for varargs以保留原始类型。只需改变:
static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1, Us... args) {
为:
// Receive varargs as forwarding references to allow perfect forwarding instead
// of receiving them as copies
static void bar(T& oT0, T& oT1, const T& iT0, const T& iT1, Us&&... args) {
并改变:
Foo<Ts...>::bar(args...);
为:
// Per earlier link, must explicitly template std::forward call in varargs case
Foo<Ts...>::bar(std::forward<Us>(args)...);
应正确接收和转发varargs,因此它们在嵌套调用中被接收为最内层“真实”调用所需的任何类型(const
或非 - const
引用)。