Question

I'm struggling with multiple inheritance with variadic templates.

This is my code so far:

template <typename U>
    class id_map {
    public:
    std::vector<U> vec_;
};

now I want to initialize another class, which inherits multiple times from id_map, something like this:

template<typename ... T>
class constant_allkey_map : public id_map<T> ... {
private:
public:
    template <typename U>
    void push_back(U i) {
        id_map<U>::vec_.push_back(i);
    }
};

This works and I can access it just fine:

constant_allkey_map<int, long> cakm;
cakm.push_back<int>(1);

It fails when I try something like this:

constant_allkey_map<int, int> cakm;

with error

"duplicate base type id_map<int> invalid".

I did some reading and it seems I'm supposed to extend id_map templates with id parameter:

template <size_t i_, typename U>
class id_map ...

but I'm not sure how to pass that id in in inheritance part:

template<typename ... T>
class constant_allkey_map : public id_map<T> ... {

Can someone please help me? Of if I'm doing this entirely wrong, point me in the right direction?

Was it helpful?

Solution

I don't think inheritance is the right thing here. Therefor I'm proposing the following method to achieve what you want:

#include <tuple>
#include <vector>

template <typename U>
class id_map
{
public:
  typedef U value_type;

public:
  std::vector<U> vec_;
};

template<typename... T>
class constant_allkey_map
{
private:
  typedef std::tuple<id_map<T>...> tuple_t;

public:
  template<
    std::size_t Idx,
    typename U = typename std::tuple_element<Idx, tuple_t>::type::value_type
  >
  void push_back(U x)
  {
    std::get<Idx>(maps_).vec_.push_back(x);
  }

  template<
    std::size_t Idx,
    typename U = typename std::tuple_element<Idx, tuple_t>::type::value_type
  >
  U get(int i) const
  {
    return std::get<Idx>(maps_).vec_[i];
  }

private:
  tuple_t maps_;
};

Usage is pretty straightforward:

#include <iostream>

int main(int, char**)
{
  constant_allkey_map<int, long> cakm;
  cakm.push_back<0>(1);
  cakm.push_back<0>(3);
  cakm.push_back<1>(2);
  cakm.push_back<1>(4);

  std::cout << cakm.get<0>(0) << std::endl;
  std::cout << cakm.get<1>(0) << std::endl;
  std::cout << cakm.get<0>(1) << std::endl;
  std::cout << cakm.get<1>(1) << std::endl;
}

Here's a live example.

Basically you just let std::tuple do the dirty work for you. You can even just do something like this:

template<typename... T>
using constant_allkey_map = std::tuple<std::vector<T>...>;

and use std::get directly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top