The following code reports that neither class X nor Y contain nexted class T: #include <iostream> #include <vector> struct X { typedef int T; }; class Y{ }; template<typename Z> void foo(Z const& z, typename Z::T* p) { std::cout << "has Z::T" << std::endl; } template<typename Z> void foo(Z const& z, ...) { std::cout << "hasn't Z::T" << std::endl; } int main(int argc, char *argv[]) { foo( X(), 0 ); foo( Y(), 0 ); } My understanding is that the ellipsis should always have lower precedence. Thank you. You all do wonderful work!
This code compiles for me with 4.2.0 and 4.0.2. As I understand this, in the Y case the first template overload gets rejected as X::T does not exist. In the X case, the first template is an exact match so it matches that way. Also Comeau C++ accepts the code.
I'm not completely sure who's right and wrong, but here's what's happening: the second argument in the X case is an integer (the number zero), not an int*. Consequently, the first template is not an exact match, but requires a cast. Gcc then takes the second template with the ellipsis instead and produces the output ----------------- hasn't Z::T hasn't Z::T ----------------- with all versions I have here (2.95...4.2pre). If you change the last argument to (int*)0, then you get what you probably expect. For the record, I also get this here: ------------- g/x> icc -Xc -ansi x.cc g/x> ./a.out has Z::T hasn't Z::T ------------- W.
Oh, I read the bug incorrectly. As I understand it 0 is special as it is also the NULL pointer and you don't need a cast for it to assign a pointer to it. Maybe we forget to take that into account.
You don't need a cast when converting to pointer, but the data type of "0" is still int. When determining the type of a template parameter, it therefore tries to to make the template parameter 'int'.
'typename X::T*' is a non-deduced context, so should not be involved in argument deduction, and 0 is a valid null pointer constant *** This bug has been marked as a duplicate of 23055 ***