Thomas Thomas - 26 days ago 7
C++ Question

c++ variadic template: can't match function

Here is my code:


#include <iostream>
#include "Generator.h" // user-defined class

char getChar(Generator & generator)
{
return generator.generateChar();
}

char getChar(int pos, const string & s)
{
return s[pos];
}

template<typename... StringType>
void func(Generator & generator, StringType &&... str)
{
char ch;
int size = sizeof...(StringType);
// lots of things to do
if (size == 0)
{
ch = getChar(generator);
}
else
{
ch = getChar(1, std::forward<StringType>(str)...); // ERROR here
}
}

int main(int argc, char ** argv)
{
Generator generator;

func(generator);
func(generator, "abc");

return 0;
}


At the beginning I just overloaded the function
func
and I found there were many similar codes. So I'm considering using the variadic template to get a better design. (How to make a better design if two overload functions are similar)

However I don't know why there is an error:



main.cpp:27:8: error: no matching function for call to 'getChar'
ch = getChar(1, std::forward(str)...);


main.cpp:37:2: note: in instantiation of function template specialization 'func<>' requested here

func(generator);


main.cpp:6:6: note: candidate function not viable: no known conversion from 'int' to 'Generator &' for 1st argument char

getChar(Generator & generator)


main.cpp:11:6: note: candidate function not viable: requires 2 arguments, but 1 was provided char getChar(int pos, const string & s)





By the way, can I have some design to avoid using
if...else...
working with
sizeof...(StringType)
?

Answer

When a template gets expanded, the entire template code gets expanded, and compiled, in its entirety.

Let's see what happens here:

func(generator);

In the resulting template-generated function, size will be 0, and the resulting function becomes:

if (0 == 0)
{
    ch = getChar(generator);
}
else
{
    ch = getChar(1);
}

Your compilation error becomes very obvious: getchar(1); does not match any overloaded instance of getChar(). The fact that the if statement is going to always evaluate to true, and the else part will never be executed doesn't matter. The else part must still be valid C++ code, that gets compiled, and it gets optimized away (maybe) only after it is compiled. And it can't be compiled, hence the compilation error.

Now that answers your question "I don't know why there is an error". Now you know. How to fix this becomes a different question, with the answer being, depending on the exact situation, some combination of template specialization, and/or SFINAE.

It looks like the example in your question is an abbreviated example (since the template function will never work, obviously, if the parameter pack has two or more parameters). That's fine (and is 100% compliant with the spirit of showing a minimum, complete, verifiable example), but coming up with an alternative compilable version of the shown code would probably not answer your real question.