Suppose i have the following code:
template <template <typename> class T>
class A {};
template <typename T>
class B
{
A<B> instance;
};
int main()
{
B<int> instance;
}
gcc 4.7.2 and gcc 4.8.0 compiles this code ok, while icc 13.0.1 and clang 3.2 gave me an error (clang require ::B instead of B, while icc also require whitespace after < in template instantiaion).
Who's right?
I found the thread about it (Template class that refers to itself as a template template parameter?), but i can't understand 14.6.1/2 of the standard and also saw LLVM bug 14350 (http://www.mail-archive.com/llvmbugs#cs.uiuc.edu/msg21095.html). So, clang and intel wrong here?
14.6.1 says:
The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself.
The "injected-class-name" is the name of the class template (B) "injected" into the scope of the class. In other words, it refers to the use of the unqualified name B within the definition of the class B. If you use that name in a context where a template name is required: i.e., with explicit template arguments (B<int>) or as a template argument for a template which takes a template template parameter (A<B>), it should refer to the template itself.
So, gcc is right.
Also, in C++11, you should not need a space after the < in <::B>. According to section 2.5, paragraph 3, when dividing the input stream into tokens:
if the next three characters are <:: and the subsequent character is neither : nor >, the < is treated as a preprocessor token by itself and not as the first character of the alternative token <:. (<: is another way of writing [.)
Related
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.
The following code compiles on GCC (doesn't even require a recent version), but it fails on clang 3.4:
template <int N>
struct T_unsigned {
typedef typename T_unsigned<N>::Type Type;
};
template <> struct T_unsigned<8> {
typedef unsigned char Type;
};
Using the above definition of T_unsigned, GCC allows you to use "T_unsigned<8>::Type" instead of "unsigned char". When I try to compile this using clang 3.4, I get:
test.cpp:3:41: error: no type named 'Type' in 'T_unsigned<N>'
typedef typename T_unsigned<N>::Type Type;
~~~~~~~~~~~~~~~~~~~~~~~~^~~~
1 error generated.
Is clang failing to compile correct C++11 code, or is this code doing something non-standard that GCC happens to support?
In your general case T_unsigned<N>, we have:
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.
[ Example:
template <class T> class A {
static const int i = 5;
int n1[i]; // i refers to a member of the current instantiation
int n2[A::i]; // A::i refers to a member of the current instantiation
int n3[A<T>::i]; // A<T>::i refers to a member of the current instantiation
int f();
};
Within T_unsigned<N>, T_unsigned<N> is just another name for itself. So basically you have something like:
class Foo {
typedef Foo::Type Type;
};
and the "correct" error message should be approximately (http://ideone.com/FvJHBF):
prog.cpp:2:17: error: ‘Type’ in ‘class Foo’ does not name a type
typedef Foo::Type Type;
^
However, you write that you have problems with using your specialization T_unsigned<8>, which is seemingly not found by clang.
Your testcase is not too exhaustive, so my answer depends on an if-statement:
If at the point of instantiation, your specialization for N=8 is visible, than clang is doubly wrong. If not, gcc and clang should both fail, but with aforementioned error message (though the error message itself is in no way defined by the standard, so this is a tool's should, not a standard's).
The name that you use as the typedef is not dependent (see the clauses that define dependent names) and the namelookup in definition context at that place will not find a declaration. That in itself is an error already.
But since there is no declaration for the name yet, the name is also not a member of a class that is the current instantiation or a base class thereof. Therefore the name is not a member of the current instantiation and therefore we have another reason to reject it by a rule that says that if the qualifier is the current instantiation, the name either must refer to a member of that instantiation, or to a member of an unknown specialization (which would be the case if the class had dependent base classes).
Note the notion of "current instantiation": the meaning of the qualifier is fixed to refer to the result of instantiating the surrounding template, we don't wait for resolving the template arguments. Hence the term is not called "current specialization", since we know that it refers to an instantiated specialization, as opposed to a later declared explicit specialization.
The thing is different for C++03 I think. The name will be dependent and the template definition is harder to deem illformed with the rules available. The illformed, no diagnostic required, behavior will however happen when you try to instantiate the template before providing the explicit specialization. I think such code refering to itself makes no sense because you never are able to actually instantiate the template validly (and there is a rule that allows rejecting a template straight away in such cases).
It seems that clang++ (I tried clang 3.2) treats the name of a template class as a instantiated class, not a template for any occurence within the class scope. For example, the following codes
template <template <class> class T>
class A {};
template <typename T>
class B {
A<B> member;
// ^---- clang++ treats B as an instantiated class
// but I want it to be a template here
// this code could compile in g++
};
int main()
{
B<int> b;
return 0;
}
What should I do to compile that?
C++03
Resolving B that way (called the injected-class-name, an implicitly-declared member of every class including template instantiations) is intended as a convenience. I've never seen it get in the way like that!
To work around, qualify the name by adding :: before it (and if necessary, the name of the namespace).
template <typename T>
class B {
A< ::B> member; // whitespace required to prevent digraph; see comments
};
C++11
C++11 §14.6.1/1 specifies (emphasis mine)
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected- class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.
Therefore, if this problem occurs under C++11 it is a compiler bug. Workaround as above.
Note — for comparison, the corresponding paragraph in C++03 is
Like normal (non-template) classes, class templates have an injected-class-name (clause 9). The injected- class-name can be used with or without a template-argument-list. When it is used without a template- argument-list, it is equivalent to the injected-class-name followed by the template-parameters of the class template enclosed in <>. When it is used with a template-argument-list, it refers to the specified class template specialization, which could be the current specialization or another specialization.
As you can see, there's already one special case allowing the identifier to be a class or template, depending on whether it occurs in a template-name. They just added a couple more cases.
This is nonconformant behavior as of C++11 because C++11 says that the injected class name (which is a name automatically declared within the class body) is a template when it is passed to a template template parameter. So your code should only fail in a C++03 implementation.
However there is no need to open a bug report about this now. I have already done it way back.
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;
while testing with different version of g++, the following problem came up
template<class bra>
struct Transform<bra, void> : kernel::Eri::Transform::bra {
static const size_t ni = bra::A::size;
bra::A is interpreted as kernel::Eri::Transform::bra::A, rather than template argument by g++ 4.1.2. on the other hand, g++ 4.3 gets it right.
what should be correct behavior according to standard?
Meanwhile, I refactor slightly to make problem go away.
Seems to me like gcc 4.1.2 was right. §14.6.1/7 (ISO/IEC 14882, C++03):
In the definition of a class template or in the definition of a member of such a template that appears outside of the template definition, for each base class which does not depend on a template-parameter (14.6.2), if the name of the base class or the name of a member of the base class is the same as the name of a template- parameter, the base class name or member name hides the template-parameter name (3.3.7).