c++ - How come pack expanded variables do not get passed by reference? -
please consider following program:
#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; }
and commented output (debug output removed clarity available @ ideone):
( -1, 0; -97.18, 3.14159 ) // initial values ( 0, 1; -97.18, 3.14159 ) // ints set once?! floats unchanged?! ( 18, -7 ) ( 0, 1; 2.71, 9000.1 ) // ints unchanged?!
i must missing obvious here: above, calling foo<...>::bar(...)
only modifies first set of 2 non-const parameters. why values of next arguments left untouched within main
?
you need use references on varargs part of template or arguments beyond first 4 passed initial call value (copying local variables). subsequent calls mutate copied values, not original arguments passed.
since want accept rvalues of arguments, use perfect forwarding varargs preserve original types. change:
static void bar(t& ot0, t& ot1, const t& it0, const t& it1, us... args) {
to:
// receive varargs forwarding references allow perfect forwarding instead // of receiving them copies static void bar(t& ot0, t& ot1, const t& it0, const t& it1, us&&... args) {
and change:
foo<ts...>::bar(args...);
to:
// per earlier link, must explicitly template std::forward call in varargs case foo<ts...>::bar(std::forward<us>(args)...);
which should receive , forward varargs correctly, received in nested calls whatever type (const
or non-const
reference) innermost "real" call requires.
Comments
Post a Comment