3

I'm having an issue with C++ templates. Here is an explanation of what I am attempting to do, so that everyone can have a better understanding of my problem.

My framework has a base class, Component, and users of my framework will derive Component to create concrete Components such as TransformComponent and AudioComponent. A ComponentComposite stores a list of all the concrete Components that a given user has created.

I am attempting to store a list of the concrete Components via boost::any and boost::any_casts.

Below are two methods in ComponentComposite and my list of boost::any.

    class ComponentComposite {

        public:
            ComponentComposite();
            template<class T> bool addComponent(T* component);
            template<class T> T* getComponent();

        private:
            QList<boost::any*>* m_components;
    }

This is example code of a GameObject, which is a ComponentComposite. I am trying to add two Components to the GameObject, and I am then trying to access the two Components that were added. Doing such will be common use-cases for ComponentComposite.

    GameObject::GameObject() : ComponentComposite()
    {
        addComponent<Components::AudioComponent>(new Components::AudioComponent());
        addComponent<Components::TransformComponent>(new Components::TransformComponent());
        Components::TransformComponent* transform= getComponent<Components::TransformComponent>();
        Components::AudioComponent* audio= getComponent<Components::AudioComponent>();
    }

Doing this proceeds to throw four errors (one for each function call):

  1. ...undefined reference to `bool BalaurEngine::Composites::ComponentComposite::addComponent<BalaurEngine::Components::AudioComponent>(BalaurEngine::Components::AudioComponent*)'
  2. ...undefined reference to `bool BalaurEngine::Composites::ComponentComposite::addComponent<BalaurEngine::Components::TransformComponent>(BalaurEngine::Components::TransformComponent*)'
  3. ...undefined reference to `BalaurEngine::Components::TransformComponent* BalaurEngine::Composites::ComponentComposite::getComponent<BalaurEngine::Components::TransformComponent>()'
  4. ...undefined reference to `BalaurEngine::Components::AudioComponent* BalaurEngine::Composites::ComponentComposite::getComponent<BalaurEngine::Components::AudioComponent>()'

If anyone would like, I can post the source code for my methods template<class T> bool addComponent(T* component); and template<class T> T* getComponent();

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Alex
  • 599
  • 1
  • 4
  • 16
  • 2
    Are your templated methods defined in the header? – David May 05 '12 at 14:41
  • Dave, I am confused as to what you are asking. The code I supplied for `ComponentComposite` is a snipped of my header. The code I supplied for `GameObject` is simply an example constructor – Alex May 05 '12 at 14:50
  • The source code for your methods addComponent and getComponent should probably be in the same .h file as where you defined class ComponentComposite. If instead you put them in the .cpp file (which is what you'd commonly do for non-template methods), you would get the error messages you've seen. – Scott Langham May 05 '12 at 14:52
  • 2
    Does this help? [Why should the implementation and the declaration of a template class be in the same header file](http://stackoverflow.com/questions/3749099/why-should-the-implementation-and-the-declaration-of-a-template-class-be-in-the) – Bo Persson May 05 '12 at 14:53
  • The unity tag is for Microsoft Unity. Don't misuse it. – Lex Li May 07 '12 at 03:24
  • 2
    Since all your concrete component classes derive from `Component`, why use `boost::any`? Why not just use a list of pointer-to-`Component`, and use `dynamic_cast<>` to look up components by type in `ComponentComposite::getComponent()`? – j_random_hacker May 07 '12 at 03:33
  • 1
    C++'s `dynamic_cast<>` requires the class to be polymorphic. `Component` does not have any `virtual` methods and is thus not polymorphic. Unless I am misunderstanding `dynamic_cast<>`, I don't think that solution will work. – Alex May 08 '12 at 04:06
  • @Alex: Yes, `dynamic_case` requires `Component` to be polymorphic. My next question is: why *isn't* it? AFAICT you either want to be able to sometimes treat derived objects abstractly as `Component`s (in which case it should be polymorphic and should have some virtual methods supplying a useful `Component` interface) *or* there is no reason for the concrete components to inherit from a common base class at all (in which case continue using `any<>`). – j_random_hacker May 08 '12 at 10:40
  • @Alex: Also please write "@j_random_hacker" somewhere in your response, otherwise I don't get a notification. – j_random_hacker May 08 '12 at 10:42
  • @j_random_hacker, the engine I am developing is still at an early stage. Because of this, things are subject to change and `Component` might become polymorphic. However, as of now, the only shared functionality between `Component`s is their ability to be enabled and disabled. This is done in an `abstract class`, `Component`, so that functionality comes implemented for any derived `Component`. If the `abstract class Component` becomes beefier and polymorphic, I will certainly use `dynamic_cast` -- `boost::any` isn't very elegant, nor is it easy on the eyes! – Alex May 08 '12 at 13:32
  • @Alex: Can you post the definition of the addComponent and getComponent? You don't have to post the entire method bodies, I just wanted to see if the method signatures looked correct. Looks like the compiler can't find them for some reason. – Mutmansky May 09 '12 at 20:19
  • @Mutmansky, I was unaware that the implemented templated function in C++ needs to be in the header, along with the definition of the templated function. After I did this, as per Scott Langham's advice, the compiler error vanished. If you would like to see the source code for the file, I'd gladly post it here/message it to you. Let me know! – Alex May 10 '12 at 03:00

1 Answers1

0

This has now been answered - see the last comment:

@Mutmansky, I was unaware that the implemented templated function in C++ needs to be in the header, along with the definition of the templated function. After I did this, as per Scott Langham's advice, the compiler error vanished. If you would like to see the source code for the file, I'd gladly post it here/message it to you. Let me know!

Graham Asher
  • 1,648
  • 1
  • 24
  • 34