I try to compile the following C++ code:
struct A {
template< bool x >
bool fun() {
return x;
}
};
template< typename T >
struct B {
struct A2 {
template< bool x >
bool fun() {
return x;
}
};
void test() {
A a;
A2 a2;
a.fun< true >();
a2.fun< true >();
}
};
The compiler complains that:
source_file.cpp: In member function ‘void B<T>::test()’:
source_file.cpp:22:24: error: expected primary-expression before ‘)’ token
a2.fun< true >();
^
However the line just above (a.fun< true >()) compiles just fine. Interestingly, if I remove the line template< typename T >, then compilation succeeds. However that line is required for reasons that do not appear from the minimal (not) working example. What is wrong here?
In this context A2 is actually a shorthand for B<T>::A2. Since A2 is a type dependent on the template parameter T, you have to refer to its member templates with an explicit template keyword
a2.template fun< true >();
A is not a dependent type and its member templates can be referred to with "plain" syntax without that extra template keyword.
See 14.2/4 and a similar example there
14.2 Names of template specializations [temp.names]
4 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 expression of the postfix-expression is type-dependent 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.
Otherwise the name is assumed to name a non-template. [ Example:
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
—end example ]
I must be missing something obvious here because this really came to me as a surprise.
The following code gives me the error: error: missing template arguments before ‘a’
template<int n=0>
class A {};
...
A a;
...
Is there a reason why a template with 1 parameter declared with a default value has to be instantiated specifying a value for it?
Can someone quote the standard?
A is still a template class. But you can omit the template parameter though:
template<int n=0>
class A {};
int main() {
A<> a;
// ^^
return 0;
}
See the live demo.
I think1 the relevant standard section is here
14.7 Template instantiation and specialization
...
3 An explicit specialization may be declared for a function template, a class template, a member of a class
template or a member template. An explicit specialization declaration is introduced by template<>. In
an explicit specialization declaration for a class template, a member of a class template or a class member
template, the name of the class that is explicitly specialized shall be a simple-template-id. In the explicit specialization declaration for a function template or a member function template, the name of the function
or member function explicitly specialized may be a template-id.
[Example:
template<class T = int> struct A {
static int x;
};
template<class U> void g(U) { }
template<> struct A<double> { }; // specialize for T == double
template<> struct A<> { }; // specialize for T == int
template<> void g(char) { } // specialize for U == char
// U is deduced from the parameter type
template<> void g<int>(int) { } // specialize for U == int
template<> int A<char>::x = 0; // specialize for T == char
template<class T = int> struct B {
static int x;
};
template<> int B<>::x = 1; // specialize for T == int
— end example ]
1)Sorry, I can't find a better standard cite / example. It doesn't cover exactly the OP's case, but demonstrates at least the same, that templates still need the <> angle brackets to be identified as templates (classes or functions).
possible workaround if it's important to disguise the nature of your object:
// the template class
template<int n=0>
class ReallyA {};
// an alias for the common case
using A = ReallyA<0>;
A a;
This is how the standard library defines std::string, for example.
using string = basic_string<char>;
Draft N3337 of the C++11 standard states in [namespace.udecl]
A using-declaration introduces a name into the declarative region in which the using-declaration appears.
Every using-declaration is a declaration and a member-declaration and so can be used in a class definition.
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the
class being defined.
This is generally used to make a protected typedef within a base-class public in the derived class, as in the following example, which compiles successfully in the latest version of Clang:
struct A
{
protected:
typedef int Type;
};
struct B : A
{
using A::Type;
};
B::Type x;
The using-declaration can refer to a template class. This compiles:
struct A
{
protected:
template<typename T>
struct Type
{
};
};
struct B : A
{
using A::Type;
};
B::Type<int> x;
It's also possible to refer to a template in a dependent base-class. The following compiles successfully (with the typedef commented.)
template<typename T>
struct A
{
protected:
template<typename U>
struct Type
{
};
};
template<typename T>
struct B : A<T>
{
using /* typename */ A<T>::Type; // A<T> is dependent, typename required?
// typedef Type<int> IntType; // error: unknown type name 'Type'
};
B<int>::Type<int> x;
Uncommenting the typename causes an error when instantiating B<int>: "error: 'typename' keyword used on a non-type".
Uncommenting the typedef causes an error when parsing B before its first instantiation. I'm guessing this is because the compiler does not treat Type as a dependent type-name.
The last paragraph of [namespace.udecl] suggests that using-declarations may specify dependent names, and that the typename keyword must be used in order to disambiguate further usage of the name introduced:
If a using-declaration uses the keyword typename and specifies a dependent name (14.6.2), the name introduced
by the using-declaration is treated as a typedef-name
My reading of [temp.dep] suggests that A<T>::Type is a dependent name. It follows logically that the name introduced by the using-declaration should also be dependent, but [temp.dep] does not explicitly mention the case of a dependent using-declaration. Am I missing something?
The problem is that Type is not a class, but a class template. You can do the following (this way you tell the compiler that Type is a class template in scope of B):
template<typename T>
struct B : A<T>
{
using A<T>::Type;
typedef typename B::template Type<int> IntType;
};
Actually, in your second example in order to write typedef for IntType you'd have to do the same.
Yes, a class-member using-declaration with a dependent qualified-id introduces a dependent name.
[namespace.udecl]
A using-declaration introduces a name into the declarative region in which the using-declaration appears.
If the name introduced is dependent, it stays dependent - I can find nothing to suggest otherwise.
However, the using-declaration syntax does not provide a way to specify that a dependent name is a template. Subsequent references to the dependent name Type within B may or may not refer to a template, so Type<int> cannot be parsed.
The following example demonstrates valid usage of a dependent using-declaration.
template<typename T>
struct A
{
protected:
struct Type
{
typedef int M;
};
};
template<typename T>
struct B : A<T>
{
using typename A<T>::Type;
typedef typename Type::M Type2;
};
B<int>::Type2 x;
I've got a templated class having two template paramters
template <class T, class U> class A /* ... */
and another template class that accepts a template class with two arguments as template parameter.
template <class T, class U, template<class X, class Y> class Z>
class B
{
typedef typename Z<T,U>::pointer pointer;
};
Is it impossible to create an instance of B in A where Z is A?
template <class T, class U>
class A
{
public:
B<T,U,A> foo (void) // compiler complaining here
{
B<T,U,A> test; // and here
return test;
}
};
A free function doing the same thing isn't problematic at all.
template<class T, class U>
B<T, U, A> bar (void)
{
B<T,U,A> test;
return test;
}
In other words: Is there any rule I didn't fell over yet that prevents me from using the name of the class I am in as a template argument?
The code is:
template <class T, class U, template<class X, class Y> class Z>
class B
{
typedef typename Z<T,U>::pointer pointer;
};
template <class T, class U>
class A
{
public:
B<T,U, A> foo (void)
{
B<T,U,A> test;
return test;
}
};
template<class T, class U>
B<T, U, A> bar (void)
{
B<T,U,A> test;
return test;
}
int main (void)
{
return 0;
}
And the MSVC 2012 compiler gives a Compiler Error 3200.
'A<T,U>' : invalid template argument for template parameter 'Z', expected a class template
Your compiler, MSVC, seems to follow the general rule laid down in §14.6.2.1/1 C++11:
A name refers to the current instantiation if it is, [...] in the definition of a class template, [...] the injected-class name [...] of the class template [...]
Inside the definition of class template A, the name A can be used because it is "injected" into the local (class) scope of A. Therefore, and famously, you can use A as well as A::A, as well as A::A::A and so on, to refer to A. By the rule quoted above, all of these expressions refer to the current instantiation (i.e. a specific type like A<int,float>), and not to the name of template A itself.
However, there is another rule, in §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 [...] as a template-argument for a template template-parameter [...] 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 <>.
(Note that in C++03, there is no such exception for template template parameters; 14.6.1/1, in fact, is worded entirely differently. Under C++03, MSVC's interpretation of the rules was probably correct.)
Given the C++11 rule, however, in the member declaration
B<T,U,A> test;
inside the definition of A, the name A is clearly used as an argument for a template template parameter and therefore must be interpreted as template name, not as type name referring to the current instantiation.
However, it is not uncommon that compilers are confused in situations like this. There are two valid ways to tell them how to interpret A:
Using the so-called normal name ::A rather than the injected one:
B<T,U,::A> test;
This is possible because of §14.6.1/5 (which was 14.6.1/2c in C++03):
When the normal name of the template (i.e., the name from the enclosing scope, not the injected-class-name) is used, it always refers to the class template itself and not a specialization of the template. [...]
Using the injected one explicitly, but designating it as a template:
B<T,U,A::template A> test;
Both methods have been confirmed as solving this problem in MSVC.
If class A is defined before class B, I'm getting the error: 'B' does not name a type (in other words, B is not defined yet). Is this the error you are getting? It can be fixed either by placing B in front of A, or, if the two are referencing each other, by forward-declaring class B before A like this:
template <typename T, class U, template<typename X, class Y> class Z> class B;
This is the statement from ISO C++ Standard 14.6/6:
Within the definition of a class template or within the definition of a member of a class template, the keyword typename is not required when referring to the unqualified name of a previously declared member of the class template that declares a type. The keyword typename shall always be specified when the member is referred to using a qualified name, even if the qualifier is simply the class template name. [Example:
template<class T> struct A {
typedef int B;
A::B b; // ill-formed: typename required before A::B
void f(A<T>::B); // ill-formed: typename required before A<T>::B
typename A::B g(); // OK
};
The keyword typename is required whether the qualified name is A or A<T> because A or A<T> are synonyms within a class template with the parameter list <T>. ]
Is this statement is true while inheritance?
If yes, can anyone explain this?
I checked with inner class; it is accepted? But I am unable to check with inheritance?
Yes, that is equally true of inherited members.
The keyword typename is required for members of base templates, but not base classes in general. The reason it is required for base templates is that their members are not automatically brought into the scope of the class {} block, so the only way to refer to them is with a qualified-id, which requires typename.
template< typename >
class base1
{ typedef int type1; };
class base2
{ typedef int type2; };
template< typename A >
class derived
: base1< A >, base2 {
typename base1< A >::type1 x;
type2 y;
};