可变参数类参数成员变量的异构存储

时间:2014-07-18 18:14:14

标签: c++ templates tuples variadic-templates heterogeneous

我有一个可变参数类模板,用于为可变数量的类创建顶级类。要进入顶级类的每个类都派生自基类,因为它们具有通用功能。我不知道将派生类存储在父类中的最佳方法,但仍然能够访问派生类的完整功能。

如果我将可变参数args存储在向量中,它们都将被存储为基类,我无法访问派生的功能。如果我将它们存储在一个元组中,我无法弄清楚如何通过派生类型访问这些函数。如果我尝试访问它们as discussed here on SO那么make_unique不可用(C ++ 14?)。

所以,我想做以下事情:

class BaseElement {
public:
    virtual int polymorphicFunction() {return 0;};
};

class DerivedElement1 : public BaseElement {
public:
    virtual int polymorphicFunction() {return 1;};
}

class DerivedElement2 : public BaseElement {
public:
    virtual int polymorphicFunction() {return 2;};
}

template<typename... systems>   // systems will always be of derived class of BaseElement
class System {
    System() : subsystems(systems{}...) {} ;  // all variadic elements stored in tuple
    // tuple used below, the system elements don't need to be stored in a container, I just want to access them 
    // I'd be happy to use a vector or access them directly as a member variable
    // provided that I can access the derived class.  I can't use RTTI.
    const std::tuple<systems...> subSystems;

    // pointer or reference, I don't mind, but pd1/2 will always exist, 
    // (but perhaps be NULL), even if there is no derived element passed to the template parameter
    DerivedElement1 *pd1; 
    DerivedElement2 *pd2;
};

//Desired usage
System<DerivedElement1> sys;  // sys->pd1 == &derivedElement1WithinTuple, sys->pd2 == NULL
System<DerivedElement2> sys;  // sys->pd2 == &derivedElement2WithinTuple, sys->pd2 == NULL
System<DerivedElement1, DerivedElement2> sys;  // sys->pd1 == &derivedElement1WithinTuple, sys->pd1 == &derivedElement1WithinTuple

有没有人对我如何做到这一点有任何建议?

1 个答案:

答案 0 :(得分:1)

使用:

#include <cstdint>
#include <type_traits>
#include <tuple>

namespace detail
{

template <typename T, typename... Ts> struct get_index;

template <typename T, typename... Ts>
struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};

template <typename T, typename Tail, typename... Ts>
struct get_index<T, Tail, Ts...> :
    std::integral_constant<std::size_t, 1 + get_index<T, Ts...>::value> {};

template <typename T>
struct get_index<T> : std::integral_constant<std::size_t, 0> {}; // Not found


template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>& t) noexcept
-> typename std::enable_if<N < sizeof...(Ts), decltype(&std::get<N < sizeof...(Ts) ? N : 0>(t))>::type
{
    return &std::get<N>(t);
}

template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>&) noexcept
-> typename std::enable_if<sizeof...(Ts) <= N, nullptr_t>::type
{
    return nullptr;
}

}

你可能有:

template <typename... systems>
class System {
public:
    constexpr System() :
        subSystems(),
        pd1(detail::safe_get<detail::get_index<DerivedElement1, systems...>::value>(subSystems)),
        pd2(detail::safe_get<detail::get_index<DerivedElement2, systems...>::value>(subSystems))
    {}

    const std::tuple<systems...> subSystems;
    const DerivedElement1 *pd1;
    const DerivedElement2 *pd2;
};