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.
Related
Is this necessary:
template <typename T>
class A{
T*point;
A<T> someFunction(){} //instead of returning just "A", not "A<T>"
}
Will someFunction implicitly return the A of the same type as the class being defined? Because outside the class, you can only refer to this type as A<float> or similar, so I'd assumed this was necessary inside the class as well. I discovered it compiles without the <> so this made wonder if it is a safe habit to omit the brackets.
It's valid and safe C++ to omit the template parameters inside the class definition. In fact it's good practice, since you might add other template parameters with default values later on. You might forget to change A<T> to A<T,SomeOtherParameter> and get strange compile-time errors. Then just returning A will do it.
You can say either A<T> or just A, and A means the same as A<T>. This is because of 14.6.1/1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name [...] is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.
Is this necessary:
template <typename T>
class A{
T*point;
A<T> someFunction(){} //instead of returning just "A", not "A<T>"
}
Will someFunction implicitly return the A of the same type as the class being defined? Because outside the class, you can only refer to this type as A<float> or similar, so I'd assumed this was necessary inside the class as well. I discovered it compiles without the <> so this made wonder if it is a safe habit to omit the brackets.
It's valid and safe C++ to omit the template parameters inside the class definition. In fact it's good practice, since you might add other template parameters with default values later on. You might forget to change A<T> to A<T,SomeOtherParameter> and get strange compile-time errors. Then just returning A will do it.
You can say either A<T> or just A, and A means the same as A<T>. This is because of 14.6.1/1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name [...] is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.
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 [.)
Given:
template <typename T>
class C {
C & operator ++ () { ... }
};
Why/how is C allowed to declare variables and functions of type C rather than being required to name C<T>? I had not really thought about it before working on a template with many parameters that would make spelling out the "self type" inconvenient.
Are there any quirks of this I should know about?
[n3290: 14.6.1/1]: 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 <>.
Ostensibly, it's merely a convenience feature.
It's just syntactic sugar.
It is convenient to not have to change the signatures of your methods if you have to change the template parameters.
Why/how is C allowed to declare variables and functions of type C rather than being required to name C?
It's just specified like this. The name of the template is injected in its body and means the actual type (with arguments).
Are there any quirks of this I should know about?
Nothing serious. You just have to remember this doesn't work for base classes, so to do CRTP, you have to do
template <class T>
class A : public Base<A<T> > // not Base<A>
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.