3

I have a data container which has following requirements:

  • Be fast: Hence templates and not normal inheritance
  • Use different implementations
  • Be able to extend those implementations with more methods
  • Data is specified via template argument and needs to be able to save pointers to data container items

The solution I have come up with is as follows:

    template<typename T, template<typename> class container_t>
class data_c
{
public:
    typedef data_c<T, container_t> value_type;
    typedef typename container_t<value_type>::ref container_ref;

    container_ref link;
    T c;
};

template<typename T>
class storage_container_impl
{
public:
    typedef T value_type;
    typedef storage_container_impl<T>* ref;
    T data;
};

template<typename _impl>
class storage_container : public _impl
{
public:
    typedef typename _impl::value_type value_type;
    typedef typename _impl::ref ref;
};

template<typename T>
using impl_storage_container = storage_container<storage_container_impl<T> >;

typedef impl_storage_container<data_c<int, impl_storage_container> > c_storage_container;

int main()
{
    c_storage_container tmp;
    tmp.data.c=5;
    tmp.data.link=&tmp;
    return tmp.data.c;
}

Which results in following error (gcc 4.7):

test1.cpp:6:48: error: no type named 'ref' in 'impl_storage_container<data_c<int, impl_storage_container> > {aka class storage_container<storage_container_impl<data_c<int, impl_storage_container> > >}'

It works if I use T *data instead of T data (But I do not want that indirection), or if I do not use storage_container_impl and have T data directly in storage_container. Using storage_container_impl mixin-style does not solve the problem as well. As container_ref is a pointer, there also should be no reason why it does not work, e.g. because there is a loop in the template declaration. This is a minimized version of the problem. Any help would be appreciated!

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
UrOni
  • 431
  • 4
  • 9
  • I'd guess that at the point where `data` is declared `data_c` is instantiated, which in turn refers to `storage_container`, which is not complete at that point yet. Clang doesn't accept it as well, which I take as indication that it's in fact illegal. – Philipp Jul 18 '12 at 20:56
  • So ... your container should contain a single instance of a wrapper type, containing a single instance of the value type and a back pointer to the container. Is that really right? – Useless Jul 18 '12 at 20:56
  • Obvious question: have you measured that virtual polymorphism would indeed be too slow in your case? – Philipp Jul 18 '12 at 20:57
  • @Philipp No I didn't, but I'm working with someone else's code and he chose the template route. If this is illegal, I'll just save `link` as `void*` and cast, I think. – UrOni Jul 18 '12 at 21:09
  • I can't quote the standard, but if Clang and GCC agree there's a change they're right :) When I tried to formulate `data_c` using the "normal" CRTP (without a template template parameter), I think I encountered an endless type recursion. That might indicate that C++ actually doesn't allow this structure (although it's possible that it allows more type recursion with template template parameters, I know too little about them to say for sure). – Philipp Jul 18 '12 at 21:15
  • "*I'll just save `link` as `void*` and cast*" No, please don't -- this completely defeats the purpose of using templates for type safety. – ildjarn Jul 18 '12 at 21:16

1 Answers1

1

I know that it's not a perfect solution, but you can try to replace

typedef impl_storage_container<data_c<int, impl_storage_container> > c_storage_container;

with

typedef impl_storage_container<data_c<int, storage_container_impl> > c_storage_container;

It compiles and work. Otherwise you get endless type recursion.

Pawel Zubrycki
  • 2,703
  • 17
  • 26