You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// The following is SFINAE'ed out if T is A
template
void f(typename T::A*);
// The following is not when T is A
template
void f(typename T::type*);
int main() {
f(0);
}
Clang says
main1.cpp:14:3: error: call to 'f' is ambiguous
f(0);
^~~~
main1.cpp:7:6: note: candidate function [with T = A]
void f(typename T::A*);
^
main1.cpp:11:6: note: candidate function [with T = A]
void f(typename T::type*);
^
And the Standard says at [class.qual]p2
"In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C [...] if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C [...] the name is instead considered to name the constructor of class C.".
A constructor is an acceptable lookup result for a "typename ...", since function names are not ignored in a typename-specifier during lookup (see the clearifying note at p2). Clang restricts that replacement to situations where constructors can be declared only, though.
The above code is accepted by comeau online compiler. Usually I found GCC rejects all the cases I expect it to for the constructor name replacement (i.e it acts not like clang in this regard), but GCC also rejects the above code. But that is because GCC ignores function names in a typename-specifier lookup, not because it wouldn't do the constructor-name replacement in general.
The text was updated successfully, but these errors were encountered:
template<class T>
struct A { };
int main () {
A<int>::A a; // ill-formed, inaccurately accepted
A<int>::A<float> b; // ill-formed, inaccurately accepted
}
The above snippet is a reduced testcase for what Johannes Schaub has explained.
We shall not be able to write A<int>::A x; (because A<int>::A would denote the constructor of A<int>, not the type itself).
Likewise, A<int>::A<float> y; shall not compile (for the same reason); A<int>::A denotes the constructor, not the injected-class-name acting as a template-id.
Extended Description
The following looks well-formed
struct A {
typedef A type;
};
// The following is SFINAE'ed out if T is A
template
void f(typename T::A*);
// The following is not when T is A
template
void f(typename T::type*);
int main() {
f(0);
}
Clang says
main1.cpp:14:3: error: call to 'f' is ambiguous
f(0);
^~~~
main1.cpp:7:6: note: candidate function [with T = A]
void f(typename T::A*);
^
main1.cpp:11:6: note: candidate function [with T = A]
void f(typename T::type*);
^
And the Standard says at [class.qual]p2
"In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C [...] if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C [...] the name is instead considered to name the constructor of class C.".
A constructor is an acceptable lookup result for a "typename ...", since function names are not ignored in a typename-specifier during lookup (see the clearifying note at p2). Clang restricts that replacement to situations where constructors can be declared only, though.
The above code is accepted by comeau online compiler. Usually I found GCC rejects all the cases I expect it to for the constructor name replacement (i.e it acts not like clang in this regard), but GCC also rejects the above code. But that is because GCC ignores function names in a typename-specifier lookup, not because it wouldn't do the constructor-name replacement in general.
The text was updated successfully, but these errors were encountered: