C ++ Variadic模板参数和元组迭代

时间:2014-08-05 16:35:14

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

此问题从here开始,与通过模板定义元组元素时访问元组元素有关。

如果我有访问元组内容的方法:

#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;
}

}

我想在这里访问元组元素,但是每个元组元素都是通过模板创建的。因此:

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

};

template <uint32_t exampleParameter = 1>
class DerivedElement1 : public BaseElement {
public:
    DerivedElement1() : i(exampleParameter) {}
    virtual int polymorphicFunction() {return 1;};
    uint32_t i; /// just used as a placeholder to demo use of parameter

}

template <uint32_t exampleParameter = 2>
class DerivedElement2 : public BaseElement {
public:
    DerivedElement2() : i(exampleParameter) {}

    virtual int polymorphicFunction() {return 2;};

    uint64_t i; /// just used as a placeholder to demo use of parameter (class is different to DE1)
}

template<typename... systems>   // systems will always be of derived class of BaseElement
class System {
    System() : subsystems(systems{}...),
    pd1(detail::safe_get<detail::get_index<DerivedElement1, systems...>::value>(subSystems)),
    pd2(detail::safe_get<detail::get_index<DerivedElement2, systems...>::value>(subSystems))
    {}  // all variadic elements stored in tuple

    const std::tuple<systems...> subSystems;

    DerivedElement1<> *pd1; 
    DerivedElement2<> *pd2;
};

pd1&amp; pd2应设置为指向相应的派生元素(如果它们在System的声明中指定时存在),否则它们应设置为null。

当我这样做时,这是有效的:

System<DerivedElement1<>, DerivedElement2<>> sys; // sys.pd1 points to DerivedElement1<> element of tuple, sys.pd2 points to DerivedElement2<> within tuple

但是,如果我向System的声明提供变量,pd1&amp; pd2都设置为nullptr。

System<DerivedElement1<5>, DerivedElement2<6>> sys; // sys.pd1 == nullptr, sys.pd2 == nullptr

我如何获得pd1&amp; pd2指向正确的元组元素吗?

编辑以试图更清楚:

从公共类派生的不同类型存储在元组中(例如DerivedElement1&lt;&gt;,DerivedElement2&lt; 6&gt;)。我在存储类指针中应该指向元组的派生类元素。当我不使用模板参数时(即上例中的DerivedElement1&lt;&gt;),我使用的设置指针代码有效,但在使用模板参数时却没有(例如DerivedElement1&lt; 5&gt;)。

1 个答案:

答案 0 :(得分:1)

所以你需要而不是get_index

namespace detail
{

template <template<typename> class Pred, typename... Ts> struct get_index_if;

template <template<typename> class Pred, typename T, typename... Ts>
struct get_index_if<Pred, T, Ts...> :
    std::integral_constant<
        std::size_t,
        Pred<T>::value ? 0 : 1 + get_index_if<Pred, Ts...>::value>
{};

template <template<typename> class Pred>
struct get_index_if<Pred> : std::integral_constant<std::size_t, 0> {}; // Not found

}

get_index_if类型的谓词:

template <typename T> struct is_a_Derived1 : std::false_type {};
template <std::uint32_t N> struct is_a_Derived1<DerivedElement1<N>> : std::true_type {};

template <typename T> struct is_a_Derived2 : std::false_type {};
template <std::uint32_t N> struct is_a_Derived2<DerivedElement2<N>> : std::true_type {};

最后:

// helper for trailing return type... until C++14
#define Return(Ret) decltype Ret { return Ret; }

template <typename... systems>
class System {
    const std::tuple<systems...> subSystems;

public:
    constexpr System() : subSystems() {}

    auto getDerivedElement1()
    -> Return((detail::safe_get<detail::get_index_if<is_a_Derived1, systems...>::value>(subSystems)))

    auto getDerivedElement2()
    -> Return((detail::safe_get<detail::get_index_if<is_a_Derived2, systems...>::value>(subSystems)))

};

注意:由于DerivedElement1<N1>DerivedElement1<N2>是不同的类型(对于N1 != N2),唯一可能的成员类型是基类。 这里你有正确类型的getter方法(或当元素不存在时nullptr_t。)

注意:给定的谓词不支持DerivedElement1<N>的派生类。