0

Этот вопрос следует из here и связан с доступом к элементам кортежа, когда элементы кортежа определяются с помощью шаблона.C++ Variadic Template Параметр и кортеж Iteration

Если у меня есть как средство доступа к содержимому кортежа:

#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 & pd2 должен быть установлен, чтобы указать на соответствующих производных элементов, если они существуют, когда это указано в объявлении системы, в противном случае они должны быть установлены в нуль.

Это работает, когда я делаю:

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

Но если поставить переменную в декларации системы, pd1 & pd2 оба установлены в nullptr.

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

Как я могу получить pd1 & PD2, чтобы указать на правильные элементы кортежа, пожалуйста?

Редактировать, чтобы попытаться быть более ясным:

Различные типы, выведенные из общего класса, хранятся в виде кортежа (например DerivedElement1 <> DerivedElement2 < 6>). У меня есть указатели класса хранилища, которые должны указывать на элементы производного класса кортежа. Устанавливаемый код указателя у меня работает, когда я не использую параметры шаблона (т. Е. DerivedElement1 <> в приведенном выше примере), но не используется, когда я использую параметр шаблона (например, DerivedElement1 < 5>).

+2

Вам либо нужно упростить пример, либо показать фактический код, потому что это достаточно запутанно и неполно, как оно стоит. – AJG85

+0

Я боюсь, что это так просто, как и получается, и я не могу опубликовать настоящий код: по какой-то причине (и я думаю, что это потому, что я поставляю параметр шаблона, а не по умолчанию), обращаясь к элементу кортежа сбой, и я возвращаю nullptr. – John

+0

Он также не компилируется, поскольку вы передаете шаблоны DerivedElement1 и DerivedElement2 в подробности :: get_index, который ожидает параметр типа, а не параметр шаблона. –

ответ

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>.

+0

Большое спасибо, очень ценим. – John

Смежные вопросы