【问题标题】:C++ Variadic Template Parameter and Tuple IterationC++ 可变参数模板参数和元组迭代
【发布时间】:2014-08-05 16:35:13
【问题描述】:

这个问题来自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 & pd2 应设置为指向各自的派生元素,如果它们在 System 的声明中指定时存在,则应设置为 null。

这在我这样做时有效:

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

但如果我为 System 的声明提供一个变量,pd1 和 pd2 都设置为 nullptr。

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

请问如何让 pd1 和 pd2 指向正确的元组元素?

编辑以使其更清晰:

从一个公共类派生的不同类型存储在一个元组中(例如 DerivedElement1、DerivedElement2)。我在存储类指针中应该指向元组的派生类元素。当我不使用模板参数(即上面示例中的 DerivedElement1)时,我的设置指针代码有效,但当我使用模板参数(例如 DerivedElement1)时无效。

【问题讨论】:

  • 您要么需要简化示例,要么显示实际代码,因为这已经足够混乱和不完整了。
  • 恐怕这很简单,我无法发布真正的代码:出于某种原因(我认为这是因为我提供了一个模板参数,而不是使用默认值一),访问元组元素失败,我得到 nullptr 返回。
  • 它也不会编译,因为您将模板 DerivedElement1 和 DerivedElement2 传递给 detail::get_index,它需要一个类型参数,而不是模板参数。
  • 您到底在尝试什么?这是没有意义的,因为DerivedElementX 是模板,但是您将它们传递给您的类型列表搜索工具(get_index,它获取给定类型列表中传递类型的索引,不是吗?)。请更清楚。
  • 对不起 - 这里的原始问题 (stackoverflow.com/questions/24831352/…) 使用类型,因为该问题是一个简化。也就是说,DerivedElement1 是一种类型,而不是模板,DerivedElement1 也是如此(详情:stackoverflow.com/questions/24812913/…

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


【解决方案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&lt;N1&gt;DerivedElement1&lt;N2&gt; 是不同的类型(对于N1 != N2),唯一可能的成员类型是基类。 这里你有正确类型的 getter 方法(或者当元素不存在时nullptr_t)。

注意:给定的谓词不支持DerivedElement1&lt;N&gt;的派生类。

【讨论】:

  • 非常感谢,非常感谢。
猜你喜欢
  • 1970-01-01
  • 2016-09-20
  • 2017-08-29
  • 1970-01-01
  • 1970-01-01
  • 2015-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多