C ++ template template

I am trying to understand the C ++ templating patterns by implementing a generic container class. Here is the code:

    using namespace std;

    template <typename T, template <typename STORETYPE> class Container>
    class Store {
    public:
        ~Store() {};
        Store() {};
        void someFunc( const T & ) {};
        //...
    private:
        Container<T> storage;
    };




    int main(int argc, char *argv[])
    {
        Store<int,deque> myStore;   // error here, won't compile!
    }

      

The above code generates a compiler error message. Error message:

"the template template argument has different template parameters than the corresponding template template parameter. Store file aStack1;

I do not know why. What's wrong?

+3


source to share


3 answers


Your problem is that std::deque

(and other standard containers) doesn't just take one template argument. Besides the stored type, you can specify the type of the allocator functor to use.

If you don't need those extra arguments, you can just grab the Variadic template template and be on your way:

template <typename T, template <typename...> class Container>
//                             variadic ^^^
class Store {

      

If you also want to support passing optional arguments to your container type, you can forward them like this:

template <template <typename ...> class Container, typename T, typename... ContainerArgs>
class Store {
    //...
    Container<T,ContainerArgs...> storage;
};

      

Then create an instance like so:



Store<deque,int> myStore;
Store<deque,int,MyIntAllocator> mySpecialStore;

      

However, you can simply extract the template arguments using a specialization:

template <typename Container>
class Store;

template <template <typename...> class ContainerType, typename T, typename... OtherArgs>
class Store<ContainerType<T,OtherArgs...>>
{
    //...
};

      

This will create the client code like this:

Store<deque<int>> myStore;
Store<deque<int,MyIntAllocator>> mySpecialStore;
Store<T> myOtherStore; //where T is some specialized container type

      

+6


source


std::deque

defined as

template <class T, class Allocator = allocator<T> > class deque;

      

So, you have to change the definition Store

to match:



template <typename T, template <typename...> class Container>
class Store {

      

But you don't even need template template parameters for that. You can achieve even more generality by simply passing the container type as a parameter, so for example Storage

will even support std::map

:

template <typename  Container>
class Store {
public:
    using value_type = typename Container::value_type;
    ~Store() {};
    Store() {};
    void someFunc( const value_type& ) {};
    //...
private:
    Container storage;
};

Store<std::map<int, float>> myStore; 

      

+1


source


As an alternative to @ TartanLlama's answer, you can also use an alias for deque

.

template<typename T>
using deque_alias = deque<T>;

int main(int argc, char *argv[])
{
    Store<int,deque_alias> myStore;   // now it will compile!
}

      

Then the default template parameters are also used (here std::allocator<T>

). (Some compilers, like MSVC, have problems with this and won't work otherwise, as they expect two template parameters, for example here ).

+1


source







All Articles