c++ - 如何避免重复使用 "indices trick"?

标签 c++ c++14 variadic-templates idioms index-sequence

我有一个名为 memory_region 的类,有点像未类型化的 gsl::span (即它本质上是一个 void* 和一个 size_t ),我也将其用于类型删除。因此它有一个 as_span<T>()方法。

对于这个类,我有一个 std::unordered_map<std::string, memory_region> my_map - 它用于在我的不共享 header 的代码部分之间传递类型删除的跨度,因此它们无法了解彼此的类型。对其中之一的典型访问如下所示:

auto foo = my_map.at("foo").as_span<bar_t>();

这对于具有一组固定缓冲区、类型和名称的代码来说效果很好。但是 - 当我的代码缓冲区依赖于模板参数包时,事情就变得棘手了。现在,我实现了一个

std::string input_buffer_name(unsigned input_buffer_index);

函数,所以如果我有一个索引序列和我的参数包我可以做,例如

template<typename Ts..., std::size_t... Indices>
my_function(std::unordered_map<std::string, memory_region>& my map) {
    compute_stuff_with_buffers(
        my_map.at(input_buffer_name(Indices)).as_span<Ts>()...
    );
}

(这是臭名昭著的 indices trick 的变体;请注意,同一类型可能会在包中多次出现,因此我不能“将类型包装在一个元组中”并按类型访问它。)

但问题是——我的代码在模板参数中没有那个索引序列;其中大部分仅基于类型的参数包进行模板化。所以我发现自己一直在编写“辅助函数/方法”以便能够使用该索引序列,例如:

template<typename Ts..., std::size_t... Indices>
my_function_helper(
    std::unordered_map<std::string, memory_region>& my map
    std::index_sequence<Indices...>  /* unused */) 
{
    compute_stuff_with_buffers(
        my_map.at(input_buffer_name(Indices)).as_span<Ts>()...
    );
}

template<typename Ts...>
my_function(std::unordered_map<std::string, memory_region>& my map) {
    my_function_helper(
        my_map, std::make_index_sequence<sizeof...(Ts)> {}
    );
}

我该怎么做,才不会涉及那么多代码重复?

最佳答案

在这种情况下,您可以使用数组形式的简单包扩展:

template<typename... Ts>
void my_function(std::unordered_map<std::string, memory_region>& my_map) {
    using swallow = int[];
    unsigned i = 0;
    (void)swallow{0, (my_map.at(input_buffer_name(i++)).as_span<Ts>(), 0)...};
}

Demo

包扩展将按顺序展开 ([temp.variadic]),并且也会按顺序(从左到右)求值,因为我们使用的是花括号初始化列表(一个未使用的整数数组):[dcl.init.聚合]

When an aggregate is initialized by an initializer list [...] the elements of the initializer list are taken as initializers for the elements of the aggregate, in order.


回复:

But what if I need to use input_buffer_name(i) twice? e.g. if I need to use { input_buffer_name(index), my_map.at(input_buffer_name(index).as_span<Ts>()) }

我想我们可以利用逻辑与将从左到右排序的事实 ([expr.log.and]),并且 bool 值也可以提升为 int。 :

template<typename... Ts>
void my_function_v2(std::unordered_map<std::string, memory_region>& my_map) {
    using swallow = int[];
    unsigned i = 0;
    (void)swallow{0, ((std::cout<< input_buffer_name(i) << std::endl, true) && (my_map.at(input_buffer_name(i++)).as_span<Ts>(), true))...};
}

Demo 2

关于c++ - 如何避免重复使用 "indices trick"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45813673/

相关文章:

c++ - 通过指向实例的静态指针访问成员变量

c++ - for 循环崩溃... segFault c++

java - 使用 Java 增强 C++ Eclipse

C++17、LNK2019、C1001 中的 C++14 错误

c++ - 如何(优雅地)将任意数量的输入输出参数旋转到函数?

c++ - 在不创建新 int[size] 的情况下声明数组时出现 SIGSEGV 错误

c++ - 使用 `void_t` 检查类是否具有具有特定签名的方法

c++ - 如何在 C++ 的外部类构造函数中初始化嵌套类成员

c++ - 同一表达式中多个参数包的多次展开

c++ - 使用可变参数模板的基于策略的设计