0

As far as I found, there were articles about initializing a static variables in class templates. However, I´m using a normal class with member function templates, so I have to ask.

In short version(not whole class definition) I have a class that look like this:

class BatchManager
{
    private:

        static std::vector<BaseBatch_P> _BATCHES;

    public:

        template <class T>
        static void placeData(T* data){

            //Loop through the entire container
            for (auto&& b: _BATCHES)
                if (b==data){
                    dynamic_cast<Batch<T>>(b)->draw(data);
                }

            //If no bach found, create a new One
            createNewBatch(data);
        }
};

However, when I want to access the member variables inside the function, it shows: undefined reference to BatchManager::_BATCHES

Then I´ve tried the following: keep definition in class header :

 //BatchManager.h

 template <typename T>
 static void placeData(T* data);

And cpp file:

std::map<GLuint,BaseBatch_P> BatchManager::_TEXTURE_MAP;

template <typename T>
void BatchManager::placeData(T* data){

    //Loop through the entire container
    for (auto&& b: _BATCHES)
        if (b==data){
            dynamic_cast<Batch<T>>(b)->draw(data);
        }

    //If no bach found, create a new One
    createNewBatch(data);
}

It fixes the first problem, but then another appears, and it happens when I want to call my static function from the program:

BatchManager::render(_data);

Error message looks like this:

undefined reference to BatchManager::placeData<DataType>(DataType*)

How can i fix this problem? Or am I doing something wrong?

Pins
  • 217
  • 1
  • 12
  • 2
    Apart from anything else, names like \_BATCHES which start with an underscore and an uppercase letter, are reserved for the C++ implementation - you should not be creating such names in your own code. –  Mar 28 '17 at 21:07
  • I don´t know why I have such a bad habit to name my private containers with an underscore and uppercase letter. It means that it can cause some problems?(not related to this problem) – Pins Mar 28 '17 at 21:09
  • 1
    Possible duplicate of [Static member initialization in a class template](http://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template) – Richard Critten Mar 28 '17 at 21:10
  • "I don´t know why I have such a bad habit to name my private containers with an underscore and uppercase letter" - Me neither - just don't do it. Forget about underscores in variable names. –  Mar 28 '17 at 21:11
  • @RichardCritten I´ve explained it at the start of the question. – Pins Mar 28 '17 at 21:15
  • Are you initializing the static members at the start of the cpp file? Also, your first chunk of code uses `template ` while the rest uses `template ` – picklechips Mar 28 '17 at 21:17
  • No error with clang on macOS... Have you tried `BatchManager::_BATCHES` instead of `_BATCHES`? – Macmade Mar 28 '17 at 21:18
  • @picklechips Ah sorry, I didn´t see this typpo about class/typename. And yes, I´m initializing them at the start of the cpp – Pins Mar 28 '17 at 21:22
  • @Macmade Have you tried the version with definitions inside header(first one) or the second one? Also about BatchManager::_BATCHES yes I tried – Pins Mar 28 '17 at 21:23

1 Answers1

1

Something like this:

#include <vector>
#include <typeinfo>

struct BaseBatch {

    virtual const std::type_info& get_type() const = 0;
    virtual ~BaseBatch() = default;
};

template<class T>
struct Batch : BaseBatch
{

    const std::type_info& get_type() const override
    {
        return typeid(T);
    }

    void draw(T* data) {}
};

using BaseBatch_P = BaseBatch*;

class BatchManager
{
private:

    static std::vector<BaseBatch_P>& get_batches() {
        static std::vector<BaseBatch_P> _;
        return _;
    }

public:

    template <class T>
    static void placeData(T* data){

        //Loop through the entire container
        bool found = false;
        for (auto&& b: get_batches())
            if (b->get_type() == typeid(T)) {
                dynamic_cast<Batch<T>*>(b)->draw(data);
                found = true;
            }

        //If no bach found, create a new One
        if (not found) {
            get_batches().push_back(new Batch<T>);
        }
    }
};
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Woah it works, thanks! Could you please provide me some additional information about this approach? I have to admit that I see something like this for the first time. – Pins Mar 28 '17 at 21:35
  • You can't define a static member variable in the class declaration, but you can define static functions. I have no idea why - probably some historic reason why it couldn't be done 30 years ago that no-one's fixed yet. As for the rest, what you're doing is called 'duck typing' (if it looks like a duck, and quacks like a duck, it's a duck). It's 'using code to find code', which is 'evil'. This approach is not perfect. passing in a pointer to `int` will not match a batch typed for `const int`, and so on. Before I can comment further I'd need to understand what you're trying to achieve. – Richard Hodges Mar 28 '17 at 21:42
  • The main idea is to have some singleton(BatchManager) to hold a container of generic batches(this piece of code is part of OpenGL batching - for storing vertices before send it to GPU). I have it generic because sometimes I want to pass 6 vertices(so usually I will pass an arrays of structs), sometimes just 2(for drawing lines) etc. So when I need to draw something, I just call put data, it loops through the pool of already created batches and decides if the same type already exist or not(if not create a new one). BaseBatch is used just for polymorphism possibility. – Pins Mar 29 '17 at 04:04
  • So basically during the runtime let´s say I will have created 3 different batches(Vertex = struct for represent vertices): Batch, Batch, Batch and everytime i call BatchManager::placeData it will decide (based on template parameter) which specific Batch will it use. If I pass Vertex[6], it will use Batch etc. I hope it was clear enough – Pins Mar 29 '17 at 04:07