c++ - 使用可变参数模板和运行时索引构建 iterator_range

标签 c++ variadic-templates

我有一组大小相同的 vector ,我想为用户提供一个接口(interface),以获取这些 vector 子集的迭代器范围。

以下示例显示了 getRange 中有问题的行:它的想法是接收一堆类型(指定 vector 的类型)和同样多的索引(指定 vector 的位置)。代码可以编译,但问题是 i++ 永远不会按预期执行,即调用总是只有 i(等于 0)。如果用户试图获取不同的类型,这也会通过 boost::get 导致运行时错误。

这可能是一个众所周知的问题。有什么巧妙的解决方案?

#include <vector>
#include <boost/variant.hpp>
#include <boost/range/combine.hpp>

template <typename... T>
struct VectorHolder
{
    template<typename X>
    using Iterator = typename std::vector<X>::const_iterator;

    std::vector<boost::variant<std::vector<T>...> > vecs_;

    template <typename X>
    auto begin(int idx) const {
        return boost::get<std::vector<X> >(vecs_.at(idx)).cbegin();
    }

    template <typename X>
    auto end(int idx) const {
        return boost::get<std::vector<X> >(vecs_.at(idx)).cend();
    }
};

template <typename... T, typename VectorHolder>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx)
{
    assert(sizeof...(T) == idx.size());
    // Fetch a boost::iterator_range over the specified indices
    std::size_t i = 0;
    std::size_t j = 0;

    // PROBLEM: i and j not incremented as intended
    return boost::combine(
        boost::iterator_range<VectorHolder::Iterator<T>>(
            vh.begin<T>(idx[i++]), vh.end<T>(idx[j++]))...);
}

int main()
{
    VectorHolder<bool, int, double> vh;
    vh.vecs_.push_back(std::vector<int>(5, 5));
    vh.vecs_.push_back(std::vector<bool>(5));
    vh.vecs_.push_back(std::vector<double>(5, 2.2));
    vh.vecs_.push_back(std::vector<int>(5, 1));

    const std::vector<int> idx = { 0, 3 };
    for (auto t : getRange<int, int>(vh, idx))
    {
        std::cout << t.get<0>() << " " << t.get<1>() << "\n";
    }
}

最佳答案

std::index_sequence 帮助:

template <typename... Ts, typename VectorHolder, std::size_t ... Is>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx, std::index_sequence<Is...>)
{
    assert(sizeof...(Ts) == idx.size());

    return boost::combine(
        boost::iterator_range<typename VectorHolder::template Iterator<Ts>>(
            vh.template begin<Ts>(idx[Is]), vh.template end<Ts>(idx[Is]))...);
}

template <typename... Ts, typename VectorHolder>
auto getRange(const VectorHolder& vh, const std::vector<int>& idx)
{
    return getRange<Ts...>(vh, idx, std::index_sequence_for<Ts...>());
}

Demo

关于c++ - 使用可变参数模板和运行时索引构建 iterator_range,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57292333/

相关文章:

c++ - Eigen 对 Rows 模板的可变模板扩展有问题

c++ - 注册和使用使用运行时生成的 UUID 的 IDL 创建的 ActiveX/COM 组件

c++ - 创建一个包含不同驱动类元素的元组,其构造函数接收一个 int 类型,由其在元组中的索引确定

c++ - 创建具有扩展索引序列的结构

c++ - 如何使用 MinGW 编译器在 Windows 命令提示符下使用 Makefile 编译代码?

c++ - g++ 和 clang++ 不同的行为与指向可变参数模板函数的指针

c++ - 所有的模板实例都是在编译时创建的吗?

c++ - 从 python 脚本调用非返回 python 函数

c++ - 相当于 Linux 中的导入库

c++ - CMake: "make depend"的用途是什么?