Home > Net >  How to _explicitly_ instantiate a variadic template while calling it
How to _explicitly_ instantiate a variadic template while calling it

Time:10-17

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

  • Related