ZumiKua
ZumiKua

Reputation: 506

Different behavior of Visual Studio and gcc when compiling variadic templates program

I'm playing with C++11's variadic templates, and here is my code:

#include "iostream"
void func(){
    std::cout << std::endl;
}

template< typename ...Params> void func(int x, Params... params){
    std::cout << " int " << x;
    func(params...);
}
template< typename ...Params> void func(float x, Params... params){
    std::cout << " float " << x;
    func(params...);
}
template< typename ...Params> void func(const char* x, Params... params){
    std::cout << " const char* " << x;
    func(params...);
}

int main(int argc, char* argv[])
{
    func(3.14f, 5, "Test");
    getchar();
    return 0;
}

The code above can be compiled and run on Visual Studio 2013 without any problem, but if I compile it with gcc 4.6.3 (I don't have gcc environment and using online service like repl.it), this code will produce error like this:

main.cpp: In instantiation of 'void func(int, Params ...) [with Params = {const char*}]':
main.cpp:15:6:   required from 'void func(float, Params ...) [with Params = {int, const char*}]'
main.cpp:24:23:   required from here
main.cpp:11:6: error: no matching function for call to 'func(const char*&)'
  func(params...);
  ~~~~^~~~~~~~~~~
main.cpp:5:6: note: candidate: void func()
 void func(){
      ^~~~
main.cpp:5:6: note:   candidate expects 0 arguments, 1 provided
main.cpp:9:36: note: candidate: template<class ... Params> void func(int, Params ...)
 template< typename ...Params> void func(int x, Params... params){
                                    ^~~~
main.cpp:9:36: note:   template argument deduction/substitution failed:
main.cpp:11:6: note:   cannot convert 'params#0' (type 'const char*') to type 'int'
  func(params...);
  ~~~~^~~~~~~~~~~

exit status 1

Whose behavior is right? Is this code has some problem I don't acknowledge or this is a bug of gcc?

BTW: If I change func(3.14f,5,"test") into func(3.14f,5) then gcc can compile this code as well.

Upvotes: 1

Views: 134

Answers (1)

n. m. could be an AI
n. m. could be an AI

Reputation: 119847

gcc behaviour is right.

Roughly speaking, when you instantiate a template, the instantiation needs to be legal C++ code when placed where the original template definition was found. (More precisely, all names except so-called dependent names need to be resolvable at the point of template definition).

In your case, the first template instantiates to an equivalent of

void func(int x, const char *params0){
    std::cout << " int " << x;
    func(params0);
}

and the last call is not valid at the point of template definition. Indeed, the template that can handle the call does not get declared until later in the code.

VC++ is known for its non-compliant handling of templates: it only checks validity of the instantiation at the point of instantiation, not at the point of the original template definition. This code illustrates it nicely.

To bring your code to compliance, first forward-declare the templates and then define them.

Upvotes: 2

Related Questions