Following is the code and quote is from the C++ Templates by Addison Wesley :
template <typename T>
class MyClass {
typename T::SubType * ptr;
…
};
Without typename, SubType would be considered a static member. Thus, it would be a concrete variable or object. As a result, the expression
T::SubType *ptr
would be a multiplication of the static SubType member of class T with ptr.
Now when I compile that code without the keyword 'typename', the error I get is this: type 'T' is not derived from type 'MyClass<T>'
.
Is the compiler recognizing 'T'? If not, then shouldn't it be a undefined reference error? If yes, then why is this an error?
Alright here is the complete code:
#include <iostream>
#include <vector>
template <typename T> class MyClass
{
T::SubType * ptr;
};
int main ()
{
return 0;
}
The error I am getting is this:
~/Desktop/notes **g++ templates/programs/trial.cpp**
templates/programs/trial.cpp:6: error: type ‘T’ is not derived from type ‘MyClass<T>’
templates/programs/trial.cpp:6: error: expected ‘;’ before ‘*’ token
Here's another way to get the same error from g++:
class Foo { static const int x = 0;};
template <typename T> class MyClass
{
Foo::x * ptr;
};
and another:
class Foo { static const int x = 0;};
class MyClass
{
Foo::x * ptr;
};
But you get a different error for this:
// class Foo { static const int x = 0;};
template <typename T> class MyClass
{
Foo::x * ptr;
};
So:
Because T is a dependent type, g++ assumes that T::SubType
is an object that will be defined by the time second-phase lookup occurs. That's as expected, and is the usual reason that typename
is required here.
Even if T::SubType
exists and is an object, the code is still bad, just like Foo::x *ptr
is bad when Foo::x
exists and is an object. I still don't understand what the error message is about - how would it help for Foo
to be derived from MyClass
? But the error message is nothing to do with templates.
"Undefined reference" is a linker error. Since this code fails to even compile, you shouldn't expect to see "undefined reference to T" anywhere.
I don't so far see how Foo
even could be derived from MyClass
. I tried the following to see whether it would give a clue to the meaning of the original message, but it fails because MyClass
is an incomplete type, which doesn't tell me anything about what would happen if Foo
were derived from MyClass
:
class MyClass
{
class Foo: public MyClass { static const int x = 0;};
Foo::x * ptr;
};
Comeau gives far more sensible error messages for all these cases - nothing about derived types, just says that T::SubType
isn't a type. So explaining g++'s error message is going to take either knowledge or good guesses about g++ internals, and exactly where in the process of trying to parse your class template it finally gives up.
Without typename, SubType would be considered a static member. Thus, it would be a concrete variable or object. As a result, the expression T::SubType *ptr would be a multiplication of the static SubType member of class T with ptr.
This description is incorrect when applied to the example you give. In class bodies there can be no expressions, and no constructs are parsed as a multiplication. However, in the C++03 syntax, there is a construct that looks as follows
struct Base { int a; };
struct Derived : Base {
Base::a; // access-declaration
};
This construct was deprecated in C++03 but still supported, and means the same as the following
struct Base { int a; };
struct Derived : Base {
using Base::a; // using-declaration
};
Because you didn't tell the compiler that T::SubType
is a type and hence tell the compiler that it should parse it as the type of a pointer declaration, the compiler assumed that T::SubType
is the name in an access-declaration. Hence it expected a semicolon directly after it, and hence it expected that T
is a base class of MyClass<T>
(or that MyClass<T>
is a derived class of T
). The error message actually has it backwards:
if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname),
ctype))
{
cp_error ("type `%T' is not derived from type `%T'",
IDENTIFIER_TYPE_VALUE (cname), ctype);
...
}
While the macro says
/* Nonzero iff TYPE is uniquely derived from PARENT. Under MI, PARENT can
be an ambiguous base class of TYPE, and this macro will be false. */
#define UNIQUELY_DERIVED_FROM_P(PARENT, TYPE) ...
Because T::SubType
is a dependent name, you need to tell the compiler that SubType
is a type (not a static data member) by typing typename
keyword.
Read about dependent name here:
EDIT:
As for your question (which you repeated in the comment):
I think what you've posted is not the complete code. So I cannot specifically comment on that. Also, sometimes compilers aren't smart enough to point out the error in template code accurately. So I suggested you to read about dependent name and when & why typename
is required. Hopefully, after that you will not have any question!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.