简体   繁体   中英

Variadic template and type deduction issue

In question 15 of the 2012 ACCU C++ Pub quiz , I am stumped by the result.

#include <iostream>

template<typename T> void P(T x) { std::cout << x; }

void foo(char a) {  // foo 1
    P(3);
    P(a);
}

template <typename... A>  // foo 2
void foo(int a, A... args) {
    foo(args...);
    P(a);
}

template <typename... A>
void foo(char a, A... args) { // foo 3
    P(a);
    foo(args...);
}

int main()
{
    foo('1','2',48,'4','5');
}

I reasoned that it would call foo 3 , foo 3 , foo 2 , foo 3 , foo 1 , and thus give an output of 1243548 . The actual output is 12355248 , and confirmed in my debugger as following foo 3 , foo 3 , foo 2 , foo 2 , foo 1 . I cannot work out why the fourth foo call is going to foo 2 not foo 3 .

For reference, I compiled with gcc 4.8.1 g++ -g -Wall -std=c++11 -Weffc++ -Wextra -O0 /tmp/foo.cpp -o /tmp/foo and got no warnings at all.


Edit: I've just tried it on Visual Studio Express 2013, and it gives 1243548 , also with no warnings.

Is this a compiler bug in GCC / VS, or one of those awkward unspecified behaviour parts of the specification?

It looks like its the order of declaration. If you forward declare the relevant overload of foo above foo 2 then you will see the result you expected, ie put this above foo 2:

template <typename... A>
void foo(char a, A... args);

The relevant portion of the standard is in 3.4.1.4:

A name used in global scope, outside of any function, class or user-declared namespace, shall be declared before its use in global scope.

And in 14.6.4.1 Dependent name resolution:

In resolving dependent names, names from the following sources are considered:

— Declarations that are visible at the point of definition of the template.

— Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.

As args is a dependent type, name resolution only considers names visible as the point of definition of the template. foo 3 has not been declared by this point so can't be considered in overload resolution. On that basis Visual Studio appears to be wrong in allowing the use of foo 3 .

foo 2不能调用foo 3因为foo 3不在foo 2范围内。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM