c++ - 以这种方式在运行时访问元组的性能成本

标签 c++

我看到了这段代码

template<typename F, typename ... Ts, std::size_t... Is>
void visit_tuple_impl(std::tuple<Ts...>& tup, F&&f, 
    std::index_sequence<Is...>, std::size_t idx) {
    auto check_call = [&](auto & elem, std::size_t I) {
        if (I == idx)
            f(elem);
    };

    (check_call(std::get<Is>(tup), Is), ...);
}

template<typename F, typename ... Ts>
void visit_tuple(std::tuple<Ts...>& tup, std::size_t idx, F&& f) {
    using TT = std::decay_t<decltype(tup)>;
    constexpr std::size_t size = std::tuple_size_v<TT>;
    auto idxs = std::make_index_sequence<size> {};
    visit_tuple_impl(tup, std::forward<F>(f), idxs, idx);
}

    void printComponents(uInt vectorId) {
        visit_tuple(data, vectorId, [&](auto &vec) {
            for(auto &elem : vec) {
                elem.print();
                std::cout << ' ';
            }
            std::cout << '\n';
        });
    }

用法如下:

int vecId = 1;
ecsData.printComponents(vecId);

这意味着给定一个运行时变量 id ,元组内的每个类型都可以在运行时在 for 循环中使用它来访问,而不是简单地使用 std::get<2>()它不接受运行时变量作为模板参数。 所以我的问题是“在 check_call() 中使用 visit_tuple_impl lambda 的折叠表达式是否在每次调用时都会检查元组中的每个 id? 引用答案:I wouldn't be surprised if it generates a lookup table that's O(1) ,但这看起来更像是一个猜测,所以我向你们提出这个问题。

check_call()每次调用 visit_tuple_impl 时都会检查元组内的每种类型?

最佳答案

是的,这正是模板将扩展的内容。简而言之,这就是模板扩展的直接、字面结果。但无论事实是否如此,那都将是一个完全不同的故事。

编译器可以进行任何没有可观察结果的优化(前提是一切都在定义的行为范围内)。使用查找表(和一些边界检查)在这里没有可观察到的结果,因此您的编译器很可能生成基于查找表的代码,如果它足够聪明,可以弄清楚这里发生了什么,并且决定这样做。

了解您的编译器是否足够聪明,能够弄清楚正在发生的情况的唯一方法是尽可能地帮助您的编译器(例如,显式指定 const std::size_t idx 作为函数的参数),然后查看在生成的代码处。

请记住,结果可能会因优化级别和元组大小而异。这与简单的 switch 非常相似。连续 case值,其中(通常)编译器仅在存在几个值时生成一些比较,并在 case 的数量时切换到查找表。 s 跨越了某个阈值。

但是很明显,C++ 标准并不要求编译器执行所有可能的没有可观察结果但对人脑来说显而易见的优化,并且编译器不需要实现这种特定的优化。

简短的回答:看看你的编译器做了什么,这是了解的唯一方法。

关于c++ - 以这种方式在运行时访问元组的性能成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59259559/

相关文章:

c++ - 有没有办法使用 libxml2 自动检测根标签中写入的命名空间?

python - 使用 CMake 打包和安装 python 绑定(bind)

c++ - 机器唯一 ID

C++:修改一个类在另一个类中的私有(private)属性

c++ - 使用 std::vector 时处理内存

c++ - 重载类实例变量

c++ - 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique 需要

c++ - 将包含 CONST char 数组 [N] 成员的结构的聚合初始化转换为构造函数

c++ - 使用#define 时出错

c++ 模板类无法修复 ostream 和 istream 函数