Reputation: 7470
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?
Upvotes: 1
Views: 516
Reputation: 2277
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.
Upvotes: 6