How can I explicitly instantiate a variadic function while calling it ?
The following code doesn't work and the compiler says that it couldn't convert the first parameter to a string &&.
#include <iostream>
using namespace std;
template<typename ... Args>
void variadic( Args &&... args );
int main()
{
string str;
variadic<string &&, string &&>( str, ref( str ) );
}
template<typename ... Args>
void variadic( Args &&... args )
{
((cout << (void*)&args << endl), ...);
}
I have some code where the function object itself is a templated parameter which is invoked with some variadic parameters so that it has to be specialized before. Of course I could use a lambda as this parameter but maybe there's a simpler way.
CodePudding user response:
Let the compiler deduce the arguments, and print them:
#include <iostream>
using namespace std;
template<typename ... Args>
void variadic( Args &&... args );
int main()
{
string str;
variadic( str, ref( str ) );
}
template<typename ... Args>
void variadic( Args &&... args )
{
#ifdef _MSC_VER
std::cout << __FUNCSIG__ << '\n';
#else
std::cout << __PRETTY_FUNCTION__ << '\n';
#endif
((cout << (void*)&args << endl), ...);
}
This gives me:
void variadic(Args &&...) [Args = <std::basic_string<char> &, std::reference_wrapper<std::basic_string<char>>>]
Shorten std::basic_string<char> to std::string, and you get:
variadic<std::string &, std::reference_wrapper<std::string>>( str, ref( str ) );
Why do we see those?
Firstly, when you don't specify template arguments here, args acts as a forwarding reference. When receiving lvalues, those deduce the underlying template parameter to an lvalue reference, so std::string & instead of std::string (the latter would be used for an rvalue).
Secondly, std::ref() returns std::reference_wrapper<...>, so it's wrong to use std::string directly.
Also: this is not an "explicit instantiation" (that would be template void variadic<...>(...);). You're just specifying template arguments explicitly.
CodePudding user response:
Your explicit template arguments specification is not the issue here.
The problem is that neither str, nor std::ref(str) are std::string R-values (which is what std::string && mentioned in the template instantiation is).
You need to use std::move(str) to make str compatible with the function parameter of type std::string &&:
string str;
variadic<string&&>(std::move(str));
A side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
