c++ - 当 i 不是常量表达式时寻址 std::tuple 的第 i 个成员?

标签 c++ c++17

假设我有以下函数模板:

template<typename T>
void mutate(T& t) { /*...*/ }

我有以下类模板:

template<typename... Args>
class Processor {
    std::tuple<Args...> tup;

    // call mutate on the ith tuple element
    void process(size_t i) {
        mutate(std::get<i>(tup)); // ERROR
    }
}

这不起作用,因为 processi 参数不是常量表达式。 (它不能是常量表达式,因为 i 直到运行时才知道)

在不修改processmutuate的签名的情况下,是否有某种方法可以有效地完成这项工作?即如何更改 process 的实现,以便它在 tup 的第 i 成员上调用 mutate

最佳答案

您需要获取运行时索引并将其提升为常量表达式。最简单的方法就是使用 Boost.Mp11它附带了一个专门用于此目的的函数:

template<typename... Args>
class Processor {
    std::tuple<Args...> tup;

    // call mutate on the ith tuple element
    void process(size_t i) {
        mp_with_index<sizeof...(Args)>(i, [&](auto I){
            mutate(std::get<I>(tup));
        });
    }
}

mp_with_index 的作用是采用常量表达式表示最大大小 (sizeof...(Args)) 和运行时大小 (i) code>),然后使用一个整型常量调用您的可调用对象(lambda),该常量是将运行时大小提升为常量表达式。

<小时/>

这可以使用 std::index_sequence 自行实现,方法是构建函数指针数组,然后调用正确的指针:

template <size_t... Is, typename F>
decltype(auto) mp_with_index(size_t i, F f, std::index_sequence<Is...>) {
    using R = decltype(f(std::integral_constant<size_t, 0>{}));
    using P = R(*)(F&);
    static constexpr P fns[] = {
        +[](F& f) -> R { return f(std::integral_constant<size_t, Is>{}); }...
    };
    return fns[i](f);
}

template <size_t N, typename F>
decltype(auto) mp_with_index(size_t i, F f) {
    return mp_with_index(i, f, std::make_index_sequence<N>());
}

(请注意,Boost.Mp11 实现比这更好,这只是功能上正确的)。

关于c++ - 当 i 不是常量表达式时寻址 std::tuple 的第 i 个成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58585380/

相关文章:

android - 桌面版 GCM 客户端

C++。何时删除 C 样式数组以释放内存

c++ - 当返回类型是引用时有什么规则

c++ - 仅使用 C++ 中的标准库获取以毫秒为单位的当前日期和时间

c++ - 使用 C++ 处理 GPIO 按钮事件

c++ - 分配动态数组时,是否删除了前面的元素?

c++ - 与 ForwardIterator 的并行性?

c++ - 我的升序排序问题是一个好的解决方案吗?

c++ - 如何使用 C++ 模板推断编译时 const char 字符串的大小?

c++ - 最佳实践 C++ : Reuse default arguments for multiple methods