I have following C++ code:
template <typename Type, typename T>
class zz
{
};
class foo
{
template <typename T>
using zz = ::zz<foo, T>;
struct own_type : zz<double>
{
own_type():
zz<foo, double>{} {} // ERROR: needs foo arg !!
};
template <typename T>
struct zz_type_gen : zz<T>
{
zz_type_gen():
zz<T>() {}
};
zz<int> _oi;
zz_type_gen<char> _od;
};
Compiling with g++ 11, clang++ 12 and cl.exe with -std=c++20 works fine but if foo template argument is removed in line with // ERROR comment compilation fails.
This seems to indicate that zz
name is looked up first in global namespace inside nested class in case nested class (own_type
) is not template. However zz
name is looked up first in class foo
in case nested class is template (zz_type_gen
).
I could not find clear explanation on how C++ names lookup works, but intuitively this seems inconsistent.
To allow
namespace N {
struct A {int f();};
}
struct B : N::A {
int f() {return A::f()+1;}
};
without repeating the namespace qualification of A
, and for the similar case of not repeating the template arguments of a class template, each class is considered to declare itself as a member (although this syntax is also used to declare or inherit constructors).
To prevent (specializations of) dependent base classes from shadowing names used in templated classes, unqualified name lookup is performed immediately in the template definition and ignores such bases entirely. This has the odd interaction with the injected-class-name model that even a name that would obviously refer to the base in each instantiation is sought outside the class instead. This does provide consistency with the case where the dependent base is more complicated than a template-id that names some specialization of a particular class template.
Therefore, own_type
finds the injected-class-name of its base, which can be used either as a type-name (by omitting <foo, double>
) or as the template-name that ::z
is. zz_type_gen
, however, finds foo::zz
; it could use typename zz_type_gen::zz
to find the injected-class-name instead of repeating the template argument list. (C++20 dispenses with the requirement for typename
in some contexts but not others; a mem-initializer still requires it, but that was likely an oversight.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With