According to ISO 14882:2011 § 14.6.2.1:
A type is dependent if it is — a template parameter,
And according to § ISO 14882:2011 14.6:
A name used in a template declaration or definition and that is
dependent on a template-parameter is assumed not to name a type unless
the applicable name lookup finds a type name or the name is qualified
by the keyword typename.
But
template <typename T> class U
{
typename T t; // ill-formed, i have an compilier error
};
Are "dependent name" and "name used in a template declaration or definition and that is dependent on a template-parameter" the same concept?
I try to resolve my missunderstanding, since it looks as collision between assertions in standard(ISO 14882:2011 § 14.6.2.1) and example from standard T t;.
Your example code is ill-formed, because of ISO section 17.7.3 (http://eel.is/c++draft/temp.res#3): T is not a nested name-specifier.
Hence, there's no way T can be anything else but the typename T used as the template parameter. I.e. the compiler can't be mistaken, so you don't need to qualify it with the typename-specifier.
An example of a dependent type where the typename-specifier is required would be T::value_type, because the actual type/value of value_type depends on what T is. In that case you have to help the compiler out:
template <typename T> class U {
using t = T; // OK
using u = T::value_type; // ill-formed: needs typename-specifier
using v = typename t::value_type; // OK: qualified with typename keyword
};
Let's say you have the following:
class foo {
constexpr static int value_type = 7;
}
class bar {
using value_type = int;
}
This is the reason the 2nd typedef line above is ill-formed: if T is foo then value_type is not actually a type, but a constant with a very confusing name. If T is bar then all is well. But the compiler can't know this, so you have to help him out and assure him value_type is in fact a type. That also means you will be greeted with a compile error if you ever try to compile U<foo>.
Note: I used C++11 syntax for the typedefs, because I find it much more readable. The explanation above still holds if you use typedef instead of using.
Related
This bit of code compiled in C++20 (using gcc 10.1) without using the typename keyword before the dependent type std::vector<T>::iterator. Why does it compile?
#include <vector>
template<typename T>
std::vector<T>::iterator // Why does this not require "typename" before it?
f() { return {}; }
int main() {
auto fptr = &f<int>;
}
code playground
One of the new features in C++20 is Down with typename.
In C++17, you had to provide the typename keyword in nearly all† dependent contexts to disambiguate a type from a value. But in C++20, this rule is relaxed a lot. In all contexts where you need to have a type, the typename keyword is no longer mandatory.
One such context is the return type of a function in class scope, as in your example. Others include the type in a member declaration, the type on the right-hand side of a using declaration, the parameter declaration of a lambda, the type you're passing to static_cast, etc. See the paper for the full list.
† Nearly all because base-specifiers and mem-initializer-ids were always excluded, as in:
template <typename T> struct X : T::type { }; // always ok
This is okay because, well, that needs to be a type. The paper simply extends this logic (well, it has to be a type, so let's just assume it's a type) to a lot more places that have to be types.
From the reference, from c++20, in contexts where the dependent name is unambiguously a typename, the typename keyword is no longer needed. In particular:
A qualified name that is used as a declaration specifier in the (top-level) decl-specifier-seq of:
a simple declaration or function definition at namespace scope
Normally, typename is used to disambiguate between cases where an identifier may refer to a type, or may refer to something else:
template<class T>
void foo(typename T::type value) {
// ...
}
When can typename be used when an identifier is already a type?
1. Can it be used if there's already a class with this name?
class MyClass{};
void foo(typename MyClass value) {}
2. Can it be used with a template parameter that's declared as a type?
template<class T>
void foo(typename T value) {}
3. Can it be used with inner classes that are unambiguously types?
class A {
public:
class B {};
};
// Compiles; no typename necessary
void foo(A::B value) {}
// This compiles too on gcc and msvc
void bar(typename A::B value) {}
Compiler interpretation
Case 1: MSVC considers this OK; gcc and clang throw an error
Case 2: MSVC considers this OK; gcc and clang throw an error
Case 3: A::B is unambiguously a type, but gcc and clang now permit the use of typename.
The keyword typename is only permitted by the C++ syntax to introduce a template type parameter, or before a qualified name, i.e. something containing the :: token.
So your #1 and #2 are ill-formed because MyClass and T are unqualified names, not containing any ::.
Before a qualified name, the typename token is:
not allowed by the grammar before a base class name in the head of a class definition, or in combination with the class, struct, or union keywords; a qualified name is always treated as a type in these contexts
otherwise required, if the qualified name is dependent and a member of an unknown specialization
otherwise optional, whether within a template declaration or not
C++17 [temp.res]/3,5,6:
When a qualified-id is intended to refer to a type that is not a member of the current instantiation and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. ...
A qualified name used as the name in a class-or-decltype (Clause [class.derived]) or an elaborated-type-specifier is implicitly assumed to name a type, without the use of the typename keyword. In a nested-name-specifier that immediately contains a nested-name-specifier that depends on a template parameter, the identifier or simple-template-id is implicitly assumed to name a type, without the use of the typename keyword. [Note: The typename keyword is not permitted by the syntax of these constructs. - end note]
If, for a given set of template arguments, a specialization of a template is instantiated that refers to a qualified-id that denotes a type or a class template, and the qualified-id refers to a member of an unknown specialization, the qualified-id shall either be prefixed by typename or shall be used in a context in which it implicitly names a type as described above.
So your #3 is well-formed, even though the name does not depend on a template parameter and isn't even in a template declaration.
Note C++20 will add many more contexts where typename is optional even with a dependent name, because it's possible to unambiguously determine from the contexts that the name can only mean a type.
From cppreference
Usage:
In a template declaration, typename can be used as an alternative to class to declare type template parameters and template template parameters (since C++17).
Inside a declaration or a definition of a template, typename can be used to declare that a dependent name is a type.
Inside a requirements for type requirements (since C++20)
So I would say that you have no guaranties that case 1 and case 2 will compile. As they do not fall into any of these three usage cases.
And for case 3, let's see what cppreference has to say about that:
The keyword typename may only be used in this way before qualified names (e.g. T::x), but the names need not be dependent.
The keyword typename must only be used in template declarations and definitions and only in contexts in which dependent names can be used. This excludes explicit specialization declarations and explicit instantiation declarations.(until C++11)
The keyword typename can be used even outside of templates. (since C++11)
So as there is no template in your example, case 3 should be guarantied to work only since C++11
And indeed a test program compiled OK with g++ -std=c++11 but issued this warning without -std=c++11
warning: 'typename' occurs outside of a template
[-Wc++11-extensions]
Current C++ compilers (latest gcc, clang) require the typename keyword in the example below:
template<class T>
struct A
{
};
template<class T>
void f(T)
{
struct C
{
};
typedef typename A<C>::Type Type; // typename required
}
If typename is omitted gcc (4.9, 5.0) reports the error:
need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope
This example is otherwise well-formed according to my reading of the C++11 standard.
This behaviour seems to be covered by the following wording:
[temp.dep.type]/8
A type is dependent if it is
a template parameter,
a member of an unknown specialization,
a nested class or enumeration that is a member of the current instantiation,
a cv-qualified type where the cv-unqualified type is dependent,
a compound type constructed from any dependent type,
an array type constructed from any dependent type or whose size is specified by a constant expression
that is value-dependent,
a simple-template-id in which either the template name is a template parameter or any of the template
arguments is a dependent type or an expression that is type-dependent or value-dependent, or
denoted by decltype(expression), where expression is type-dependent.
However, according to [class.local] the class C is a local class rather than a nested class. If so, why should A<C> be treated as dependent?
EDIT
For bonus points, if the example is modified by adding a member enum to C as follows:
template<typename T>
struct A
{
typedef T Type;
};
template<class T>
void f(T)
{
struct C
{
enum { value = T::value };
};
typedef typename A<C>::Type Type; // typename required
}
Should A<C> now be treated as dependent?
According to my understanding (and the current wording of the standard), C in your example is not dependent. Neither is A<C>::Type, so the typename is not required.
There is a fundamental difference between nested classes of class templates and local classes in function templates: The latter cannot be specialized, thus any reference to a local class inside a function template is uniform. That is, in every specialization of f, C refers to the class C that is defined in this function template f. That is not the case with class templates as you can indeed explicitly specialize members on their own (as covered in [temp.expl.spec]
/(1.6)):
template <typename T>
class A { class C{}; };
template <>
class A<int>::C { int i; };
However:
A type is dependent if it is
a compound type constructed from any dependent type,
So if the definition was done as in dyp's example, C would be dependent as it is constructed from T.
There are unclarities in the standards wording that are being discussed in the comment section, e.g. about definitions of member functions that depend on T and how that transposes to the classes dependency.
Following is my reasoning, hope it helps. The local C does not instantiate until f instantiate. So, A<C> is not an instantiation and is opaque to the compiler when it sees it. Because of the opaqueness, the compiler cannot determine whether A<C>::Type is a nested type name or a data member or a method. However, by default, the compiler does not see A<C>::Type as a nested type name. Therefore, an explicit specification is needed.
There doesn't appear to be anything in the standard to state that the typename keyword should be necessary here. The wording does not explicitly state otherwise, either, which may have led GCC to take a bit of a shortcut in treating f<T>(T)::C (being a local class in a function template specialisation) as dependent on T — by extension, this would make A<[f<T>(T)::]C>::Type dependent.
Core defect 1484 wasn't raised for this issue specifically, but I think the additional non-normative text it proposes makes the intention clear and, were it in a standard, GCC would compliantly not require the typename keyword here.
I came across an inconsistency in the way current C++ compilers (clang/gcc) determine whether a name is dependent. In the following example, A::f is dependent but ::f is not, resulting in an error when the latter is used.
template<typename>
struct B
{
typedef int Type;
};
template<typename U>
static U f(U u);
template<typename T>
struct A
{
template<typename U>
static U f(U u);
typename B<decltype(f(0))>::Type m1; // typename required
B<decltype(::f(0))>::Type m2; // typename not required
};
The inconsistent part is that the declaration of A::f does not depend on a template parameter of A, meaning it seems unnecessary to treat it as a dependent name.
This behaviour seems to be covered by the following wording in the C++11 standard:
[temp.dep.expr]/3
An id-expression is type-dependent if it contains
an identifier associated by name lookup with one or more declarations declared with a dependent type
[temp.dep.type]/3
A type is dependent if it is
a compound type constructed from any dependent type
The declaration of ::f is clearly not dependent, as its type depends only on its own template parameters. Why should A::f be treated differently?
I think that based on the standard, f is non-dependent, actually.
14.6.2.2 Type-dependent expressions [temp.dep.expr]
3 An id-expression is type-dependent if it contains
an identifier associated by name lookup with one or more declarations declared with a dependent type,
This applies equally to the global template function as it does to the member template function: not at all. The return type of U is dependent inside the definitions of the template functions, but for the caller, the function type of f<int> has already been transformed from U(U) to int(int). At any rate, it wouldn't explain why compilers treat the two cases differently, and it also would not explain why a non-template member function is also treated as dependent.
a template-id that is dependent,
a conversion-function-id that specifies a dependent type, or
These do not apply. There is no < or > that must always be present in a template-id, and there is no conversion function being called.
a nested-name-specifier or a qualified-id that names a member of an unknown specialization;
See below.
or if it names a static data member of the current instantiation that has type "array of unknown bound of T" for some T (14.5.1.3).
This also does not apply: there are no arrays involved.
So it depends on whether f is a member of an unknown specialization. But it isn't:
14.6.2.1 Dependent types [temp.dep.type]
5 A name is a member of an unknown specialization if it is
A qualified-id in which [...].
A qualified-id in which [...].
An id-expression denoting the member in a class member access expression (5.2.5) in which [...].
These cannot apply: f is neither qualified nor part of a class member access expression.
Since the only way f can be dependent is if it is a member of an unknown specialization, and it is not a member of an unknown specialization, f must not be dependent.
As for why compilers nonetheless treat it as dependent, I have no answer. Either some part of my answer here is wrong, the compilers have bugs, or the compilers follow a different version of the C++ standard. Testing with an example that works regardless of whether names are dependent shows a few variations in compiler treatment:
#include <cstdio>
void f(const char *s, ...) { std::printf("%s: non-dependent\n", s); }
struct S1 { };
template <typename T>
struct S2 {
static S1 a;
static S1 b() { return {}; }
template <typename U>
static U c() { return {}; }
static void z() {
f("S1()", S1()); // sanity check: clearly non-dependent
f("T()", T()); // sanity check: clearly dependent
f("a", a); // compiler agreement: non-dependent
f("b()", b()); // compiler disagreement: dependent according to GCC 4.8, non-dependent according to clang
f("c<T>()", c<T>()); // sanity check: clearly dependent
f("c<S1>()", c<S1>()); // compiler agreement: dependent
f("decltype(b())()", decltype(b())()); // compiler agreement: dependent
}
};
void f(const char *s, S1) { std::printf("%s: dependent\n", s); }
// Just to show it's possible to specialize the members
// without specializing the full template.
template <>
S1 S2<S1>::b() { return {}; }
template <>
template <>
S1 S2<S1>::c<S1>() { return {}; }
int main() {
S2<S1>::z();
}
This difference in clang's treatment of b(), decltype(b())(), and c<S1>() is particularly troubling to me. It just doesn't make any sense. They're clearly all equally dependent. I can understand from an implementation point-of-view that care must be taken not to generate code for the member functions just yet because there might be specialisations of S2<S1>::b or S2<S1>::c<S1>, but that applies to all, and has no effect on the return type.
Check out the following code (written just for fun)
namespace N
{
template<typename T>
struct K
{
};
}
template<typename T>
struct X
{
typename T::template K<T> *p; //should give error
//N::K<int> has no template member named `K`
};
int main()
{
X<N::K<int> > l;
}
The code gets compiled on g++(4.5.1) and Clang whereas Comeau and Intel C++ give (similar) errors.
The errors that I get on Comeau are :
"ComeauTest.c", line 13: error: class "N::K<int>" has no member "K"
typename T::template K<T> *p;
^
detected during instantiation of class "X<T> [with T=N::K<int>]" at
line 18
"ComeauTest.c", line 13: error: expected an identifier
typename T::template K<T> *p;
^
detected during instantiation of class "X<T> [with T=N::K<int>]" at
line 18
So my question is "Is the code sample ill-formed ?" According to me "Yes". Does that mean this is yet another bug in g++/Clang?
Why GCC and Clang think they are right
K, which is the injected class name, has a dual nature in the scope of K<int>. You can use it without template arguments. Then it refers to K<int> (to its own type).
It can be followed by a template argument list too. IMO it's reasonable to say that you need to prefix it with template because of the parser ambiguity with the < that follows. It then refers to the specified type that's determined by the template arguments.
So it can be treated as a member template and as a nested type, depending on whether it's followed by a template argument list. Of course, K is not really a member template. The dual nature of the injected class name seems to me more of a hack anyway, though.
The Standard has an example that reads like this:
template <class T> struct Base { };
template <class T> struct Derived: Base<int>, Base<char> {
typename Derived::Base b; // error: ambiguous
typename Derived::Base<double> d; // OK
};
One might be inclined to conclude from this that the intent is that you could leave off the template. The Standard says
For a template-name to be explicitly qualified by the template arguments, the name must be known to refer to a template.
I can't see how this wouldn't apply to T::K<T>. If T is a dependent type then you can just lean back because you can't know what K refers to when parsing it, so to make any sense of the code, you just have to be able to prefix it with template. Notice that n3225 has that example too, but it's not a defect there: You can officially leave off template if you lookup into the template's own scope in C++0x (it's called the "current instantiation").
So until now, Clang and GCC are fine.
Why Comeau is right
Just to make it even more complicated, we will have to consider the constructors of K<int>. There is a default constructor and a copy constructor implicitly declared. A name K<int>::K will refer to the constructor(s) of K<int> unless the name lookup used will ignore function (constructor) names. Will typename T::K ignore function names? 3.4.4/3 says about elaborated type specifiers, which typename ... is one of:
If the name is a qualified-id, the name is looked up according its qualifications, as described in 3.4.3, but ignoring any non-type names that have been declared.
However, a typename ... uses different lookup. 14.6/4 says
The usual qualified name lookup (3.4.3) is used to find the qualified-id even in the presence of typename.
The usual qualified lookup of 3.4.3 won't ignore non-type names, as illustrated by the example attached to 14.6/4. So, we will find the constructor(s) as specified by 3.4.3.1/1a (the additional twist that this only happens when non-types are not ignored was added by a later defect report, which all popular C++03 compilers implement though):
If the nested-name-specifier nominates a class C, and the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (clause 9), the name is instead considered to name the constructor of class C. Such a constructor name shall be used only in the declarator-id of a constructor definition that appears outside of the class definition.
So in the end, I think comeau is correct to diagnose this, because you try to put a template argument list onto a non-template and also violate the requirement quoted in the last part (you use the name elsewhere).
Let's change it by accessing the injected name by a derived class, so no constructor name translation occurs, and you really access the type so that you really can append the template arguments:
// just replace struct X with this:
template<typename T>
struct X
{
struct Derived : T { };
typename Derived::template K<T> *p;
};
Everything compiles now with comeau too! Notice I already did problem report to clang about this exact thing. See Incorrect constructor name resolution. BTW, if you declare a default constructor in K, you can see comeau give a better error message if you use T::K<int>
"ComeauTest.c", line 13: error: overloaded function "N::K<T>::K [with T=int]" is
not a template
typename T::template K<T> *p;