Adrián
Adrián

Reputation: 85

How to correctly use variadic templates in C++11 with this simple example?

Using VS2013 (VC2012).

After reading many answers about variadic templates and failing with my own code, I want to ask about how to compile/achieve my example, which does not represent my whole need but in place I prefer to put in order to make it easier and cleaner for everyone to understand my point.

I preferably need a function which receives an arbitrary amount of (int, const char * tuples), and access any tuple from this list inside the function. Since I believe after reading over Internet this is not possible, I tried defining the variadic template with an arbitrary amount of a certain class which would contain the int and const char* members, and it fails.

Please note it's important I want to separate the declaration from the definition in different files:

phrases.h:

class CPhraseParamInfo { // Nothing, for easier example }

class CPhrases
{
    template<class... T> void Test(T... paramsInfo);
}

phrases.cpp

template<CPhraseParamInfo...> void CPhrases::Test(CPhraseParamInfo... param)
{ // Nothing, for easier example }

Errors (translated):

error C2993: 'CPhraseParamInfo' : invalid type for the template parameter '__formal' without defined type
error C3543: 'CPhraseParamInfo': doesn't contain a parameter pack
error C2244: 'CPhrases::Test' : cannot match the function definition with an existent declaration

Remember I'd prefer the first method, if possible. I hope I was clear enough.

Thanks!

Upvotes: 0

Views: 460

Answers (2)

Adri&#225;n
Adri&#225;n

Reputation: 85

Thanks @Yakk. Here is expanded example with part of my real codework in order to show how to allow a last parameter to be used as arbritrary values passing (for certain phrase va_args processing), if anyone finds it useful. The key here is to call the variadic template function with the same amount of variadic class used on the template call list (< CPhraseParamInfo, ... >):

phrases.h:

class CPhrases:
{
    template<class... ParamInfo, typename... Arg> static void 
    LoadForPlayer(CHL2RP_Player *player, char *dest, int maxlen, const char *header,
    const char *prependText, ParamInfo&... paramsInfo, Arg... args)
    {
        CPhraseParamInfo paramsInfoBuff[] = { paramsInfo... };
        LoadForPlayer(player, dest, maxlen, header, prependText, paramsInfoBuff, sizeof paramsInfoBuff, args...);
    }

    static void LoadForPlayer(CHL2RP_Player *player, char *dest, int maxlen, const char *header, const char *prependText,
        CPhraseParamInfo *paramsInfoBuff, int paramCount, ...);

    static FORCEINLINE void LoadRegionChat(CHL2RP_Player *player, char *dest, int maxlen, const char *talker, const char *message)
    {
        LoadForPlayer<CPhraseParamInfo, CPhraseParamInfo>(player, dest, maxlen, REGION_CHAT_HEADER, INDIAN_RED_CHAT_COLOR,
        CPhraseParamInfo(CPhraseParamInfo::STRING, TEAM_CHAT_COLOR "%s" DEFAULT_CHAT_COLOR), CPhraseParamInfo(CPhraseParamInfo::STRING, "%s"), talker, message);
    }
}

Upvotes: 1

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275956

The definition of a template function must be visible at the point where it is used, barring unusual cases.

You could do this:

class CPhraseParamInfo { // Nothing, for easier example }

class CPhrases {
  void Test( CPhraseParamInfo* start, CPhraseParamInfo* end );
  template<class... T> void Test(T... paramsInfo) {
    CPhraseParamInfo buff[]={paramsInfo...};
    return Test(buff, buff+sizeof...(paramsInfo));
  }
};

then in your cpp file:

void CPhrases::Test(CPhraseParamInfo* start, CPhraseParamInfo* end)
{
  // Nothing, for easier example
}

or something similar.

Upvotes: 0

Related Questions