2

I am trying to forward declare a template class then use the class to declare a member data in some other class. The code is below:

using namespace std;

template<class T>
class B;

class A{
   B<T> b;
};

template<class T>
class B{
    T x;
};

int main(){
}

I got the compilation error:

error: ‘T’ was not declared in this scope
     B<T> b;

Can anybody let me know what I did wrong and how to achieve my goal? (I noticed the posts on template class on SO, but none of them answers my question.)

Thanks a lot in advance!

leo
  • 357
  • 2
  • 15
  • 2
    Firstly, there is no `T` in the context of `A`, so you need to give it an actual type; this is the source of your compiler error and is pretty straightforward. Secondly, an incomplete type cannot be a member of `A` because it would make `A`'s size unknowable. You would need to use a pointer or reference to the incomplete type. – Peter Huene Nov 11 '15 at 16:59
  • what you trying to achieve? `class A` not template, you have no type `T` available, why you should not get error about `B b;`? – fghj Nov 11 '15 at 16:59
  • My goal: forward declare a template class B, then use it as the type of the member data b of a class A, without (1) making A a template class and (2) caring about what special type will be used upon the time of the declaration of b. – leo Nov 11 '15 at 18:01

3 Answers3

5

This:

class A{
   B<T> b;
};

should be this :

template <class T>
class A{
    B<T> b;
};

By adding B<T> into A , you basically turned A into a template class as well with the template type T, so A class deleration should be templetized as well.

David Haim
  • 25,446
  • 3
  • 44
  • 78
  • I actually do not want A be a template class, because I know that it contains a member of type B and that is it. In other words, I don't want to care about what B is when defining A. Is there anyway to achieve this? – leo Nov 11 '15 at 17:51
  • a template class neccessserly needs a template type in order to be instansiated. `B` has no meaning without a type which defines it. they are inseperatable. – David Haim Nov 11 '15 at 18:14
2

Firstly, class A is not a template. Thus, you must specialize your B object with a type (i.e, not T). Secondly, at the point of your member variable's declaration (i.e., b), B is an incomplete type. Thus, you can only have a pointer or a reference to it.

template<class T>
class B;

class A{
   B<int> *b;
     ^^^  ^
};

template<class T>
class B{
    T x;
};

Alternatively and if this doesn't cause any implications. If you want a concrete B object change the order of definition of class A and B, since in your example B doesn't relate with A:

template<class T>
class B{
    T x;
};

class A{
   B<int> b;
};

Edit:

If you don't know what special type you'll use for B (so adding "" is infeasible) at the time the declaration of b in class A. Then you have to make your class A a template as well. Doing so you can have a concrete type of B:

template<class T>
class B;

template<class T>
class A{
   B<T> b;
};

template<class T>
class B{
    T x;
};
101010
  • 41,839
  • 11
  • 94
  • 168
  • What if I don't know what special type I will use for B (so adding "" is infeasible) at the time the declaration of b in class A? I buy the second point . – leo Nov 11 '15 at 17:47
2

Edit:

Please see my comments to 101010 and David's answer. Basically, I am wondering if it is possible to achieve the following goal in C++: forward declare a template class B, then use it as the type of the member data b of a class A, without (1) making A a template class and (2) caring about what special type will be used upon the time of the declaration of b.

What you are asking for makes no sense. It's not your fault. You are just misunderstanding how C++ works. Let me explain it to you.

Forward declaration

Example:

class Foo;

To the compiler the above statement means: "There will be a class named Foo defined somewhere else". From this point and until the it's definition Foo is an incomplete type. There are things you can do with an incomplete type and there are things you can't. In particular: you can't declare variables, and member variables (aka fields) of that type. Example:

class Foo;

class Bar0
{
    Foo f;  // syntax error: Foo is an incomplete type
};

void fun0(Foo f)  // syntax error: Foo is an incomplete type
{
    Foo f;  // syntax error: Foo is an incomplete type
}

class Foo
{
    int x;
    Foo f;  // syntax error: Foo is an incomplete type
    void fun(Foo other) {  // Ok here: see "note"
    }
};  // Foo becomes complete here.
// Note: things are actually more complicated
// for example: Foo is complete inside it's own methods
// even if they are defined inside the definition of Foo.

class Bar1
{
    Foo f;  // Ok here: Foo is complete
};

void fun1(Foo f)  // Ok here: Foo is complete
{
    Foo f;  // Ok here: Foo is complete
}

One of the things you can do with an incomplete type is declare a pointer to it. For example:

class Foo;

void fun(Foo* f)  // Ok here
{
}


class Bar
{
    Foo* f;  // Ok here
};

Templates

Example:

template<class Bar>
class Foo
{
    Bar b;
};

Template class is like a blueprint that can be used to create many classes. To create a class from a template you have to substitute it's arguments with concrete values. Foo<int> and Foo<long> are two separate types.

There are two things you can do:

To be continued

Further reading:

What is the difference between a definition and a declaration: https://stackoverflow.com/a/1410632/5420829
What can you do with an incomplete type:
https://stackoverflow.com/a/553869/5420829

Community
  • 1
  • 1
  • Please see my comments to 101010 and David's answer. Basically, I am wondering if it is possible to achieve the following goal in C++: forward declare a template class B, then use it as the type of the member data b of a class A, without (1) making A a template class and (2) caring about what special type will be used upon the time of the declaration of b. – leo Nov 11 '15 at 17:53