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?.