I have the following test code
#include <iostream>
template <typename T>
struct PS
{
template <typename U>
static void foo()
{
std::cout<<"Some test code";
}
};
template <typename T>
void bar()
{
PS<T>::template foo<T>(); //won't compile without `::template`
}
int main()
{
bar<int>();
}
ISO C++03 14.2/4: says
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
The Standard talks about -> and . but not about ::. Is it a defect in the C++03 Standard or am I missing something? Someone please enlighten me.
However the wording has been changed in N3126
When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object or pointer expression of the postfix-expression or the nested-name-specifier in the qualified-id depends on a template parameter (14.6.2) but does not refer to a member of the current instantiation (14.6.2.1), the member template name must be
prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Can someone give an example to illustrate what but does not refer to a member of the current instantiation means in context of C++0x?
-PS
The Standard talks about -> and . but not about ::.
The scope resolution operator (::) is part of the qualified-id referred to by "or after nested-name-specifier in a qualified-id."
The additional verbiage in C++0x is part of the resolution to CWG defect 224. Effectively, the definition of dependent names has been changed:
The decision on whether a name is dependent or non-dependent should be based on lookup, not on the form of the name: if the name can be looked up in the definition context and cannot be anything else as the result of specialization, the name should be non-dependent.
Can someone give an example to illustrate what "but does not refer to a member of the current instantiation" means in context of C++0x?
I don't know if this is something that in fact behaves differently between an implementation of C++03 and C++0x.
template< typename Q >
struct A {
template< typename T >
void f( T );
void g() {
this->f< Q >( 5 ); // member of current instantiation is not ambiguous
A< identity<Q> >().template f< 5 >(); // suppose A is partially
// specialized on identity. Legal but confusing; need help from template keyword.
}
};
Related
template<class T>
T::type<int> f(){
}
According to [temp.names#3.4]
A < is interpreted as the delimiter of a template-argument-list if it follows a name that is not a conversion-function-id and
[...]
that is a terminal name in a using-declarator ([namespace.udecl]), in a declarator-id ([dcl.meaning]), or in a type-only context other than a nested-name-specifier ([temp.res]).
According to [temp.res#general-4.3.1], T::type<int> does satisfy the above rule(emphasized mine) due to the following rule
A qualified or unqualified name is said to be in a type-only context if it is the terminal name of
[...]
a decl-specifier of the decl-specifier-seq of a
[...]
simple-declaration or a function-definition in namespace scope,
T::type<int> is the decl-specifier of the function-definition for template function f that is in the namespace scope, hence the terminal name type is said to be in the type-only context.
Also, according to [temp.res#general-5]
A qualified-id whose terminal name is dependent and that is in a type-only context is considered to denote a type.
Hence, the symbol < in T::type<int> is interpreted as the delimiter of the template-argument-list due to [temp.names#3.4] while the qualified-id T::type<int> is considered to denote a type due to [temp.res#general-5], the example should be legal. However, it has been rejected by both Clang and GCC.
I wonder, Are both the keyword typename and template not necessary in this example compiled by future implementations?
Yes, this is the rule, and it’s correct; compilers simply haven’t implemented the (newer) template part yet. In discussing that addition, an example was brought up that illustrates the absurdity of requiring the keyword in this context:
template<typename T> struct A {
template<typename U> struct B {
B();
};
template<typename U> B<U> make();
};
template<typename T> template<typename U>
A<T>::B<U>::B() {} // no 'template' keyword required before 'B' here, but...
template<typename T> template<typename U>
A<T>::B<U> A<T>::make() { return {}; } // 'template' keyword required before 'B' here?
This also illustrates part of the motivation for dropping the requirement for typename in many contexts. A<T>::B might be a dependent name (if the declaration ends up being for something that’s not a member of (the primary template of) A), but that doesn’t interfere with parsing it since no expression can appear there.
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]
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.
Why does this work:
template <typename A>
struct S {
A a;
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
};
But this does not (a and f swapped places):
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
A a;
};
saying that a is not declared in that scope (inside decltype) but adding explicit this-> makes it work.
template <typename A>
struct S {
A a;
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
};
This works because within a trailing return type, members of the surrounding class are visible. Not all members, but only the members that are declared prior to it (in a trailing return type, the class is not considered to be complete, as opposed to function bodies). So what is done here:
As we are in a template, a lookup is done to see whether a is dependent or not. Since a was declared prior to f, a is found to refer to a class member.
By the template rules in C++, it is found that a refers to a member of the current instantiation since it is a member of instantiations of the surrounding template. In C++, this notion is used mainly to decide whether names are dependent: If a name is known to refer to the surrounding template's members, it is not necessarily needed to be looked up when instantiating, because the compiler already knows the code of the template (which is used as the basis of the class type instantiated from it!). Consider:
template<typename T>
struct A {
typedef int type;
void f() {
type x;
A<T>::type y;
}
};
In C++03, the second line declaring y would be an error, because A<T>::type was a dependent name and needed a typename in front of it. Only the first line was accepted. In C++11, this inconsistency was fixed and both type names are non-dependent and won't need a typename. If you change the typedef to typedef T type; then both declarations, x and y will use a dependent type, but neither will need a typename, because you still name a member of the current instantiation and the compiler knows that you name a type.
So a is a member of the current instantiation. But it is dependent, because the type used to declare it (A) is dependent. However this doesn't matter in your code. Whether dependent or not, a is found and the code valid.
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(a.f(b))
{
}
A a;
};
In this code, again a is looked up to see whether it is dependent and/or whether it is a member of the current instantiation. But since we learned above that members declared after the trailing return type are not visible, we fail to find a declaration for a. In C++, besides the notion "member of the current instantiation", there is another notion:
member of an unknown specialization. This notion is used to refer to the case where a name might instead refer to a member of a class that depends on template parameters. If we had accessed B::a, then the a would be a member of an unknown specialization because it is unknown what declarations will be visible when B is substituted at instantiation.
neither a member of the current, nor a member of an unknown specialization. This is the case for all other names. Your case fits here, because it is known that a can never be a member of any instantiation when instantiation happens (remember that name lookup cannot find a, since it is declared after f).
Since a is not made dependent by any rule, the lookup that did not find any declaration is binding, meaning there is no other lookup at instantiation that could find a declaration. Non-dependent names are lookup up at template definition time. Now GCC rightfully gives you an error (but note that as always, an ill-formed template is not required to be diagnosed immediately).
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(this->a.f(b))
{
}
A a;
};
In this case, you added this and GCC accepted. The name a that follows this-> again is lookup at to see whether it might be a member of the current instantiation. But again because of the member visibility in trailing return types, no declaration is found. Hence the name is deemed not to be a member of the current instantiation. Since there is no way that at instantiation, S could have additional members that a could match (there are no base classes of S that depend on template parameters), the name is also not a member of an unknown specialization.
Again C++ has no rules to make this->a dependent. However it uses this->, so the name must refer to some member of S when it is instantiated! So the C++ Standard says
Similarly, if the id-expression in a class member access expression for which the type of the object expression is the current instantiation does not refer to a member of the current instantiation or a member of an unknown specialization, the program is ill-formed even if the template containing the member access expression is not instantiated; no diagnostic required.
Again no diagnostic is required for this code (and GCC actually doesn't give it). The id-expression a in the member access expression this->a was dependent in C++03 because the rules in that Standard were not as elaborated and fine-tuned as in C++11. For a moment let's imagine C++03 had decltype and trailing return types. What would this mean?
The lookup would have been delayed until instantiation, because this->a would be dependent
The lookup at instantiation of, say, S<SomeClass> would fail, because this->a would not be found at instantiation time (as we said, trailing return types do not see members declared later).
Hence, the early rejection of that code by C++11 is good and useful.
The body of a member function is compiled as if it was defined after the class. Therefore everything declared in the class is in scope at that point.
However, the declaration of the function is still inside the class declaration and can only see names that precede it.
template <typename A>
struct S {
template <typename B>
auto f(B b) ->
decltype(a.f(b)); // error - a is not visible here
A a;
};
template <typename A>
template <typename B>
auto S<A>::f(B b) ->
decltype(a.f(b))
{
return a.f(b); // a is visible here
}
The Standard says (section 14.6.2.1):
If, for a given set of template arguments, a specialization of a template is instantiated that refers to a member of the current instantiation with a qualified-id or class member access expression, the name in the qualified-id or class member access expression is looked up in the template instantiation context.
this->a is a class-member access expression, therefore this rule applies and lookup takes place at the point of instantiation, where S<A> is complete.
Finally, this doesn't solve your problem at all, because section 5.1.1 says:
If a declaration declares a member function or member function template of a class X, the expression this is a prvalue of type “pointer to cv-qualifier-seq X” between the optional cv-qualifier-seq and the end of the function-definition, member-declarator, or declarator. It shall not appear before the optional cv-qualifier-seq
and it shall not appear within the declaration of a static member function (although its type and value category are defined within a static member function as they are within a non-static member function).
So you can't use this-> here, since it is before the cv-qualifier-seq part of the function declaration.
Wait, no it isn't! Section 8.4.1 says
The declarator in a function-definition shall have the form
D1 ( parameter-declaration-clause) cv-qualifier-seq opt ref-qualifier opt exception-specification opt attribute-specifier-seq opt trailing-return-type opt
A question regarding template disambiguator was given here:
template disambiguator
and in the answer we can read:
ISO C++03 14.2/4
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Now here comes my conrete example that I don't quite understand:
template <class T>
class Base {
public:
template <int v>
static int baseGet() {return v;}
class InnerA {
public:
template <int v>
static int aget() {return v;}
};
class InnerB {
public:
typedef Base BaseType;
typedef BaseType::InnerA OtherType;
template <int v>
static int baseGet() {return BaseType::baseGet<v>();} //(A)
template <int v>
static int aget() {return OtherType::aget<v>();} //(B)
};
};
It obviously fails to compile. You need template in the line (B): OtherType::template aget<v>();.
However, both g++ (4.4.3) and clang++ (2.9) don't complain about the lack of template in the line (A). Why? BaseType depends on the type T, does it not? Is it a small depart from the standard by those compilers, or do I misunderstand something in the standard?
They implement the C++0x specification, where Base is the current instantiation. And C++0x allows to omit template keyword in such a case. Since BaseType is a typedef for Base, when you say BaseType, that names the current instantiation too.
To quote the spec, since you seem to be interested in spec refs
A name is a member of the current instantiation if it is [...]
A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one member of the current instantiation or a non-dependent base class thereof.
and
A name refers to the current instantiation if it is [...]
in the definition of a [...] nested class of a class template, [...], the injected-class-name (Clause 9) of the class template or nested class
and (the modified 14.2/4 that you quoted)
[...] or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. [...]
Note: In C++03 your code is ill-formed because both BaseType and OtherType are dependent. The spec says:
A type is dependent if it is [...]
a template parameter
a qualified-id with a nested-name-specifier which contains a class-name that names a dependent type
a template-id in which either the template name is a template parameter or any of the template arguments is a dependent type
(note that Base is equivalent to Base<T>, which is the base on which Base and BaseType::InnerA are dependent types).
Note that "explicitly depends" in your quote is a pre-standard term, and was gotten rid of fairly lately (I believe it was at December1996). It basically meant (in this context) a qualified-id in which the qualifier is dependent or a class member access (a->x / a.x) where the a was dependent. After "explicitly depends" was removed from the draft, it was still lurking around at some places, and even C++0x has still references to "explicitly depends" in a note at 14.6.2p2:
the base class name B<T>, the type name T::A, the names B<T>::i and pb->j explicitly depend on the template-parameter.
Because OtherType is a nested dependent name while BaseType is not a nested type to begin with.
You need to use template for nested dependent types.
The keywords here are:
Dependent Type
Nested Type
If a type is both, then you've to use template.
OtherType is both dependent type (it depends on T) as well as nested type
BaseType is only dependent type (it depends on T). Its not a nested type.
BaseType does depend on the type T- but so does InnerB. In effect, from the perspective of any code inside BaseType<T>, it does not depend on T.