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:
Name binding and dependent names (C++ only)
Dependent Names (scroll down and read this section - better if you read the complete article)
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!
Related
Here's my problem. I got the following error if I don't put template argument explicitly in derived::getType() function.
class template argument deduction is only available with -std=c++1z or -std=gnu++1z
But even with -std flag, it still fires error.
class myT {
// full implementation
};
template<class T>
class base {
public:
virtual my_getter_type<T>* getter() = 0;
}
class derived : public base<myT> {
public:
my_getter_type<myT>* getter(); // this is OK, no compile error
my_getter_type* getType(); // this is NOT OK, compile error
}
You're overthinking it. The return type must be a type, obviously. my_getter_type<myT>* is a type. my_getter_type is a template.
my_getter_type* doesn't make sense either, because to form a pointer type the * has to follow a base type.
There is no inherent connection between the return type of a function in a base class and the return type of a function with the same name in a derived class. That is, it's perfectly legal to do this:
struct base {
int f();
};
struct derived : base {
double f();
};
Making f() virtual in the base doesn't change that.
Same thing with the return type of getter() in the question; the base class version returns my_getter_type<T>, but that does not mean that the derived version must also return my_getter_type<T>; again, it would be perfectly legal for the derived version of getter() to return my_getter_type<T*>, int, void, or anything else.
And, of course, my_getter_type is a template, not a type, so cannot be a legal return type.
How can I return a "B" type using a method of an "A" class? For example:
template <typename T> class A{
//something
template <typename V> class B{
//something
};
B& foo(){
B<T> y; //the variable must have the same type T of the father class (for my exercise)
//something
return y;
}
};
main:
A <int> o;
o.foo();
Once I try to compile it, it gives me these errors:
"invalid use of template-name 'A< T >::B' without an argument list" at "B& foo()..."
and
"'class A' has no member named 'foo'"
I have written the function "foo" after closing the class B, so it might be right...
There are three problems with your code:
The public access specifier is missing. foo() won't be accessible outside class A otherwise.
You need to add the template arguments to the return type as well, i.e. declare the member function as B<T> foo(). Even better, let the compiler deduce the return type (works with C++14 and beyond), so just write auto foo()
You are returning a reference to a local variable, which leads to undefined behavior. Just return the local variable as value, due to copy elision you won't need to worry about performance issues.
With that in mind, your code should work.
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 8 years ago.
Why can't a C++ compiler recognize that g() and b are inherited members of Superclass as seen in this code:
template<typename T> struct Superclass {
protected:
int b;
void g() {}
};
template<typename T> struct Subclass : public Superclass<T> {
void f() {
g(); // compiler error: uncategorized
b = 3; // compiler error: unrecognized
}
};
If I simplify Subclass and just inherit from Subclass<int> then it compiles. It also compiles when fully qualifying g() as Superclass<T>::g() and Superclass<T>::b. I'm using LLVM GCC 4.2.
Note: If I make g() and b public in the superclass it still fails with same error.
This can be amended by pulling the names into the current scope using using:
template<typename T> struct Subclass : public Superclass<T> {
using Superclass<T>::b;
using Superclass<T>::g;
void f() {
g();
b = 3;
}
};
Or by qualifying the name via the this pointer access:
template<typename T> struct Subclass : public Superclass<T> {
void f() {
this->g();
this->b = 3;
}
};
Or, as you’ve already noticed, by qualifying the full name.
The reason why this is necessary is that C++ doesn’t consider superclass templates for name resolution (because then they are dependent names and dependent names are not considered). It works when you use Superclass<int> because that’s not a template (it’s an instantiation of a template) and thus its nested names are not dependent names.
Konrad's answer doesn't ask or answer the final "why" in all of this. It's not just the C++ committee arbitrarily saying "hey, give up on dependent names, nobody likes them anyway". Rather, the compiler does some checking of the templates even before they're instantiated, and it can't make any sense of g() or b until it knows T, as it can't - in general - select between possible specialisations of the base class (e.g. SuperClass<X> may have int b while SuperClass<Y> has void b() and SuperClass<Z> doesn't have b at all). The more explicit forms are just saying "trust me - this must come from the base class at instantiation time (otherwise there'll be a compiler error then)".
I am using code::blocks, with, I believe gcc. Given the example code (this is pseudo code and may not replicate the problem):
//Assume this is in a separate header file to B
class TestA
{
protected:
int A;
public:
void Function1(){A = 0;}
};
class TestB : public TestA
{
public:
void CallFunction(){ A = 10; Function1();}//
};
I would get similar compile errors, like:
Error: 'A' not declared in this scope.
Error: Function1() not declared in this scope.
I was under the impression that all base variables and functions were inherited to the subclass. Given the base class has a lot of functions and variables, I don't want to use the 'using' keyword as I'd have to declare it for every function and variable (to my knowledge).
Is there any way to make it so TestB explicitly or actually includes the stuff it's inheriting?
Relevant snippets below
Okay. It's not possible to include example code as it's in project, but I will quote the key snippets:
C:\Users\user\Desktop\Projects\RND2\TemplateListAdv.h|30|error: 'Size' was not declared in this scope|
The line this is on is:
if(!Array.SetToSize(Size))
The class it's in is:
template<typename TemplateItem>
class TemplateListAdv : public TemplateList<TemplateItem>
And the incriminating line from TemplateList is:
SIZE_TYPE Size; //SIZE_TYPE is unsigned long.
//SIZE_TYPE is available in all files as unsigned long.
Files go:
TemplateList.h->TemplateBasics.h->TemplateListAdv.h
No missing files from what I can see.
I will tack in, the 'using' keyword resolves it individually, but this has been bugging me as I thought inheritance was automatic.
Compiler data as requested:
"Release 10.05 rev 6283 (2010-05-27 09:09:13) gcc 4.4.1 Windows/unicode - 32 bit"
So it looks like you are getting error wite template classes inheritance, isn't it? They are a big difference comparing to non-template ones. Assuming you have code like this:
template <class T>
class TestA
{
protected:
int A;
public:
void Function1(){A = 0;}
};
template <class T>
class TestB : public TestA<T>
{
public:
void CallFunction(){ A = 10; Function1();}//
};
The issue is caused by two-phase name lookup. All members of the base TestA class are dependent names, i.e. they depend on the template argument T. This is so because you can have template specialization for TestA with totally different members, e.g.:
template <class T>
class TestA
{
protected:
int A;
public:
void Function1(){A = 0;}
};
template <class T>
class TestB : public TestA<T>
{
public:
void CallFunction(){ A = 10; Function1();}//
};
template <>
class TestA<int>
{
};
Now, there is no A and Function1 members in the TestA, so they would be unaccessible in TestB as well. In order to let compiler know that these members are indeed depende on the template argument you should write TestB like this:
template <class T>
class TestB : public TestA<T>
{
public:
void CallFunction(){ this->A = 10; this->Function1();}//
};
This way you make compiler resolve names only during template instantiation time instead of template declaration time and it will known about base class members.
One thing to add is that there is no such issue with VC compiler, it doesn't try to parse templates until instantiation and thus don't support two-phase name lookup.
The problem that you're having about accessing base class stuff in a class template, is a FAQ item.
Rather then quoting the whole FAQ item here, I just link to it: that's your answer.
The code that you presented to illustrate the problem was unrelated, sorry. It is always a good idea to give an actual example rather than an example of what one thinks might be the problem.
Cheers & hth.,
The problem is that you are using templates, and the base class is a 'dependent name'. That is, the template base class could be specialized and not have the Size member, the compiler just doesn't know when it compiles your class, because the Size reference is not in a dependent context.
In your particular case the easiest solution is to refer to the inherited members using this:
if(!Array.SetToSize(this->Size))
And since this is a dependent name, it should work
Are you sure that :
Size is a protected or public attribute of TemplateList ?
you're not calling if(!Array.SetToSize(Size)) from a static method ?
The question is really bad, and you might want to improve on that. Anyway, my crystal ball tells me that Size is defined in a base template, and that because the identifier Size is not dependent lookup is not going into the base template and the compiler not seeing it. Add a this-> before Size and you should be set.
When interpreting a template member function, the compiler must (following the standard) decide for each symbol if it is dependent on the template parameter. If it is dependent on it, then it'll only be resolved when the template is instantiated. However, he must resolve it at this moment.
In your case, the compiler think that A and Function1 don't depend on the template parameter and should thus be resolvable just after the parse. You just have to make it depend on the template parameter by using this->A and this->Function1
So, you should have something like that.
template < typename T >
class Base
{
protected:
int A;
public:
void Function1() { A = 0; }
};
template < typename T >
class Derived : public Base< T >
{
public:
void CallFunction1() {
this->A = 10;
this->Function1();
}
};
I understand that the member names of a base-class template are hidden within the scope of a derived class, and therefore must be accessed using this->foo or Base<T>::foo. However, I recall that C++ also allows you to use the using keyword, which can come in handy in a derived-class function which frequently accesses a base-class variable. So, in order to avoid cluttering up the function with this-> everywhere, I'd like to use the using keyword.
I know I've done this before, but for whatever reason I can't get it to work now. I'm probably just doing something stupid, but the following code won't compile:
template <class T>
struct Base
{
int x;
};
template <class T>
struct Derived : public Base<T>
{
void dosomething()
{
using Base<T>::x; // gives compiler error
x = 0;
}
};
int main()
{
Derived<int> d;
}
The error, (with GCC 4.3) is: error: ‘Base<T>’ is not a namespace
Why doesn't this work?
It doesn't work because C++ language has no such feature and never had. A using-declaration for a class member must be a member declaration. This means that you can only use in class scope, but never in local scope. This all has absolutely nothing to do with templates.
In other words, you can place your using-declaration into class scope
struct Derived : public Base<T> {
...
using Base<T>::x;
...
};
but you can't have it inside a function.
Using-declarations for namespace members can be placed in local scope, but using-declarations for class members cannot be. This is why the error message complains about Base<T> not being a namespace.
Outside class scope (if you are in a block etc), you can only name namespace members in a using declaration.
If you don't want to place that using declaration into the scope of Derived (which IMO is the favorable solution), your other option is to use a reference
int &x = this->x;
x = 0;
It should be noted that this is semantically different, because it
Forces a definition to exist for Base<T>::x, which might not be the case for static const data members
Forces Base<T>::x to be of type int& or be convertible to type int&.
Otherwise, if you want to avoid using this-> all again, I don't see other options.
template <class T>
struct Base
{
int x;
};
template <class T>
struct Derived : public Base<T>
{
using Base<T>::x;
void dosomething()
{
x = 0;
}
};
int main()
{
Derived<int> d;
}
As others said, it is working only class scope.