0

I have the following code (it's on ideone.com):

template<class T>
class CMemoryPool
{
public:
    CMemoryPool(int param1)
        : stuff(param1)
    {}

private:
    T stuff;
};

template<class T>
class CList
{
public:
    struct Entry
    {
        T data;
    };

    static CMemoryPool<Entry> s_pool;
};

template<class T>
CList<T>::CMemoryPool<CList<T>::Entry>::s_pool(1);

int main()
{
    CList<int> list;
}

I can't seem to get the initialization of s_pool outside of the class to compile. Can anyone help me figure out how to make this work? Note I'm using C++03 only.

void.pointer
  • 24,859
  • 31
  • 132
  • 243
  • http://stackoverflow.com/questions/185844/initializing-private-static-members – Jeef Mar 28 '14 at 13:33
  • This has been asked many times: - http://stackoverflow.com/questions/185844/initializing-private-static-members - http://stackoverflow.com/questions/8461546/c-initializing-static-variable – Jeef Mar 28 '14 at 13:34
  • 1
    **this is for a template class, your links to the simple scenarios do not answer my question** – void.pointer Mar 28 '14 at 13:36
  • Just use the Template type of T – Jeef Mar 28 '14 at 13:38
  • Pretty sure you need a `typename` for `CList::Entry`, but unfortunately [this also didn't fix it](http://ideone.com/RpysDz) :( ... – πάντα ῥεῖ Mar 28 '14 at 13:43

3 Answers3

2

I think that you forgot how initializing a static data member works in general:

struct Data { int i; };

struct Holder { static Data StaticMember; };

Data Holder::StaticMember = { 1 };
^    ^~~~~~~~~~~~~~~~~~~~ static member qualified name
\~~~ static member type

If you look at your declaration, it is striking that you forgot one of the two above:

// Only a single element: there should be a type and a name
template<class T>
CList<T>::template CMemoryPool<typename CList<T>::Entry>::s_pool(1);

// Two elements
template<class T>
CMemoryPool<typename CList<T>::Entry> CList<T>::s_pool(1);
^                                     ^~~~~~~~~~~~~~~~ name
 \~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ type

Once corrected it just works

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • The code itself is fairly obfuscated so I missed an basic and fundamental piece. – void.pointer Mar 28 '14 at 14:03
  • 1
    Yes, that's the problem with the spaces popping within types: it looks right, but in fact isn't. What clued me in is that in your declaration somehow `CMemoryPool` ended up as a nested type inside `CList` which seemed fishy and I had to step back to realize what was truly happening. – Matthieu M. Mar 28 '14 at 14:19
1

EDIT: I was under the impression that:

You must explicitly give value to the static value for each instantiation of the template:

CList<int>::CMemoryPool<CList<int>::Entry>::s_pool(1);

must be somewhere in your *.C files...

Alternatively, use a static local variable in a method of the table used to get the value.

But after playing a bit, this seems to compile in ideone

template<class T>
CMemoryPool<typename CList<T>::Entry> CList<T>::s_pool(1);

I still recommend @FredOverflow solution as it protects your from static initialization problems

jsantander
  • 4,972
  • 16
  • 27
  • Most other template statics can be initialized with type `T`, so why do I need to do it explicitly for each type in this case? – void.pointer Mar 28 '14 at 13:35
  • Ah I feel stupid now! The static initialization statement was missing its type! Great job! – void.pointer Mar 28 '14 at 13:55
  • 1
    @RobertDailey ... still... I'm not sure how this would play when this template is properly defined on its *.h file and included in multiple places... anyone knows? – jsantander Mar 28 '14 at 14:05
1

Static data members inside class templates are somewhat of a pain to initialize. I suggest a factory function instead. Then you don't need to worry about defining the variable somewhere else.

Just rewrite the line

static CMemoryPool<Entry> s_pool;

to

static CMemoryPool<Entry>& s_pool()
{
    static CMemoryPool<Entry> foobar;
    return foobar;
}

And then use s_pool() instead s_pool everywhere. You get lazy initialization as a benefit.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Doesn't answer my question – void.pointer Mar 28 '14 at 13:38
  • @FredOverflow probably you're missing `static CMemoryPool foobar(1);` that would replace the original `CList::CMemoryPool::Entry>::s_pool(1);` – jsantander Mar 28 '14 at 13:42
  • @RobertDailey I've been playing around with your code a bit, and couldn't get it syntactically right. I'd say Freds answer well answers your question, or let's better say: solves your problem elegantly. – πάντα ῥεῖ Mar 28 '14 at 13:46
  • I'm not looking for an elegant solution, this is an experiment for me (learning exercise). I found this problem and can't solve it, would be nice to see the solution. I understand there are alternative ways to do the same thing, but that's not what I'm asking for. – void.pointer Mar 28 '14 at 13:53