Consider the following code:
#include <iostream>
#include <tuple>
#include <utility>
// A.
template <typename... Args>
void f (const char* msg, Args&&... args)
{
std::cout << "A. " << msg << "\n";
}
// B.
template <typename... Args>
void f (const char* msg, std::tuple<Args...>&& t)
{
std::cout << "B. " << msg << "\n";
}
struct boo
{
const std::tuple<int, int, long> g () const
{
return std::make_tuple(2, 4, 12345);
}
};
int main ()
{
f("First", 2, 5, 12345);
f("Second", std::make_tuple(2, 5, 12345));
boo the_boo;
f("Third", the_boo.g());
f("Fourth", std::forward<decltype(std::declval<boo>().g())>(the_boo.g()));
return 0;
}
The output of that will be:
A. First
B. Second
A. Third
A. Fourth
From the output it's evident that it does not do what I would like it to do, that is I would like Third and Fourth to go through the B. version of the function. The std::forward from the Fourth call is superfluous as perfect forwarding does not happen there. In order to have perfect forwarding I know:
- I must have an rvalue reference in a type deducing context
- the type of the parameter must be a template type for the function
I understand it does not work. But I do not fully grasp:
why the context is changed by using std::tuple in such a way that it fails to work as desired ? Why the template parameter cannot be the type for another templated type?
how can I(elegantly) fix it ?