1

I'm trying to understand how templates work, and I've come up with this problem. Now, I'm perfectly aware that it can be solved using polymorphism, but I'm curious to see if it can be solved by just using templates. The situation is as follows:

Suppose I have two types of queues, which are defined as follows:

#include <queue>
template <typename GenType, typename Comparator>
class Priority
{
public:
    Priority()
    { }
    ~Priority()
    { }
    void insert(GenType const& t)
    { mQueue.push(t); }
private:
    std::priority_queue<GenType, std::vector<GenType>, Comparator> mQueue;
};

template<typename GenType>
class FIFO
{
public:
    FIFO()
    { }
    ~FIFO()
    { }
    void insert(GenType const& t)
    { mList.push_front(t); }
private:
    std::deque<GenType> mList;
};

And now, I have a class that can use either Queue or FIFO (or any other type of queue) as shown here:

// I'm not sure that this is how it should be declared...
template <typename GenType, 
    template<typename, typename...> class List>
class User
{
public:
    User()
    { }
    ~User()
    { }
    void add(GenType const& t)
    { mList.insert(t); }
private:
    // This line gives an error.
    List mList;
};

As it stands, the marked line gives an error, which I understand since I haven't actually passed any template parameters to List. The thing is that I don't know how to solve this error.

To give some context, the use case for this was to be able to have the User class take a any type of queue and could be used like this:

User<int, FIFO> u1;
// Not sure if it is this way:
User<int, Priority, std::less<int>> u2; 
// Or this way:
User<int, Priority, std::less> u2;

Any suggestions on how to solve this problem?

1
  • @Rakete1111 why yes, yes it is. I'll fix it right now. Commented Sep 24, 2016 at 17:06

2 Answers 2

1

Don't do it that way.

Instead, let your User class template take the full type of the container it's going to use, and let the container indicate what type of values it takes:

template <typename Container>
class User
{
public:
    using value_type = typename Container::value_type; // you'll have to add this
                                                       // typedef to your containers

    User() = default;
    ~User() = default;

    void add(value_type const& t)
    {
        mList.insert(t);
    }

private:
    Container mList;
};

This way, I, as the user of your class template, can provide the right thing. If I want to use your priority queue, I can pass in the comparator I want directly:

User<Priority<int, std::less<>>> u;

Or not:

User<FIFO<int>> u2;

Or maybe I wrote my own container which isn't even a class template:

User<SpecialContainer> u3;

Yours works either way. Generic is good.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks! I've been trying to figure this out for a while, and I never thought of something so simple.
1

There is already an accepted answer, but I'd like to show the desired syntax.

private:
    // This line doesn't give an error.
    List<GenType> mList;
};

Now this line compiles too:

User<int, FIFO> u1;

The last two lines can't be compiled because the template User accepts only two parameters. Just add a third parameter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.