如何区分存储在模板化类

时间:2016-03-25 19:19:29

标签: c++ templates c++11 variadic-templates variant

假设我有一个假装是其模板包中的类型之一的类,我如何获得函数中一个模板参数所在的索引或当前索引指向的类型?

template<typename... Vs>
struct TypeIndex {

    int index_of_type;

    void some_function() {
        cout << static_cast<get_type_from_index()> (some_member);
    }
};

我知道这里需要进行一些类专业化,但我不能完全理解它将如何在代码中实现。任何帮助都会很棒,谢谢!

2 个答案:

答案 0 :(得分:3)

  

获取函数中一个模板参数所在的索引

有两百万种方法可以做到这一点。这是一个:

// base case is "not found"
template<size_t N, class T, class... Ts>
struct index_of_impl : std::integral_constant<std::size_t, std::size_t(-1)> {};

template<size_t N, class T, class... Ts>
struct index_of_impl<N, T, T, Ts...> : std::integral_constant<std::size_t, N> {};

template<size_t N, class T, class U, class... Ts>
struct index_of_impl<N, T, U, Ts...> : index_of_impl<N+1, T, Ts...> {};

template<class T, class... Ts>
struct index_of : index_of_impl<0, T, Ts...> {};
  

当前索引的类型指向

索引的值仅在运行时已知且C ++是静态类型的,因此这是不可能的。

对于编译时索引,它是微不足道的:

template<size_t I, class... Ts>
using at = std::tuple_element_t<I, std::tuple<Ts...>>;
  

但是boost::variant如何使用apply_visitor执行此操作   功能

apply_visitor的想法是将其编译为switch - 类似的构造:

// pseudocode
switch(index) {
    case 0:
        return visitor(get<0>(variant));
        break;
    case 1:
        return visitor(get<1>(variant));
        break;
    // etc.
};

请注意,visitor需要在变体中使用每个类型,并且在每种情况下都返回相同的类型,这就是上述工作的原因。

当然,实际上如果可能的类型数量无限制,你就不能写switch(在C ++ 03中 - 没有可变参数模板 - boost::variant显然有一个上限它可以处理的类型数量,因此如果需要,可以直接写switch。最简单的方法是简单地尝试每个索引,直到找到正确的索引。草图:

template<size_t N>
struct impl {
    template<class Visitor, class Variant>
    decltype(auto) apply(Visitor visitor, const Variant& variant){
        if(variant.index == N) return visitor(get<N>(variant));
        return impl<N-1>::apply(visitor, variant);
    }
};

template<>
struct impl<0>{
    template<class Visitor, class Variant>
    decltype(auto) apply(Visitor visitor, const Variant& variant){
        assert(variant.index == 0);
        return visitor(get<0>(variant));
    }
};

template<class Visitor, class Variant>
decltype(auto) apply_visitor(Visitor visitor, const Variant& variant){
    return impl<variant_size<Variant>::value>::apply(visitor, variant);
}

有更有效的方法(例如,进行二分查找,或使用跳转表)。

答案 1 :(得分:2)

下面的课程正在使用代码来回答您的其他问题。我没有包含它,因为依赖它的析构函数调度尚未实现。

使用它:using my_type = pack_type_at<index, Vs...>::type;,其中index是编译时可用的整数,例如模板参数。

在upvoting之前注意:这仅适用于编译时索引,因此它没有完全回答这个问题。在其他地方,我说任务是“非常重要的”,因为需要使用运行时索引以某种方式找到并运行与其中一个包索引相对应的相应函数重载。

template <int IDX, int CURI, bool ATIDX, typename V, typename ...Vs>
struct pack_type_at_helper {
    typedef typename pack_type_at_helper<IDX, CURI+1, CURI+1==IDX, Vs...>::type type;
};

template <int IDX, int CURI, typename V, typename ...Vs>
struct pack_type_at_helper<IDX, CURI, true, V, Vs...> {
    typedef V type;
};

template <int IDX, typename ...Vs>
struct pack_type_at {
    typedef typename pack_type_at_helper<IDX, 0, IDX==0, Vs...>::type type;
};