【问题标题】:Variadic template for taking multiple containers references用于获取多个容器引用的可变参数模板
【发布时间】:2019-02-14 09:24:57
【问题描述】:

我希望有一个函数获取对容器的多个引用并返回所有容器的元素组合。由于此操作是在一个非常热的循环中执行的,我希望能够静态展开尽可能多的操作,而无需编写 5 个基本相同的函数实例。

我正在执行的算法基本上表现为

const auto result = s0 + a1 * s1 + a2 * s2 + ...

所有si 都是包含所有相同数量元素的容器。要求和的元素数量在编译时是已知的。

我正在寻找的函数应该表现为:(假设)

inline Container sum(const Container& s0, double a1, const Container& s2, ....){
    auto result = Container(s0);
    for (int i = 0; i < result.size(); ++i)
        result[i] += a1 * s1[i] + a2 * s2[i] + ...;
    return result;
}

出于性能原因,不希望编写带有运行时边界检查的内部循环。此外,在尝试使用运行时边界时,我遇到了无法轻松地将可变数量的引用传递给函数的问题,在这种情况下我应该只求助于指针吗?

所有代码都必须是有效的 C++11,我无法在这个项目中使用更现代的编译器。

【问题讨论】:

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


    【解决方案1】:

    我会将doublecontainer 分组以将代码简化为:

    template <typename C, typename ... Cs>
    C sum(const C& c0, const Cs&... cs)
    {
        auto result = c0;
        for (int i = 0; i < result.size(); ++i)
    #if 0 // C++17
            result[i] += (cs[i] + ...); 
    #else // C++11/C++14
            const int dummy[] = {0, (static_cast<void>(result[i] += cs[i]), 0)...};
            static_cast<void>(dummy); // avoid warning for unused variable.
    #endif
        return result;
    }
    

    因此,对于分组,类似于:

    template <typename C>
    struct MulContainer
    {
        auto operator [](int i) const { return d * c[i]; }
    
        double d;
        const C& c;
    };
    

    所以是调用,而不是

    sum(c0, a1, c1, a2, c2);
    

    你会:

    sum(c0, MulContainer{a1, c1}, MulContainer{a2, c2});
    

    如果真的需要,使用std::index_sequence 您可能仍然有第一次调用语法。

    template <typename C, std::size_t... Is, typename Tuple>
    C sum_impl(const C& c0, std::index_sequence<Is...>, const Tuple& t)
    {
        return sum(c0, MulContainer{std::get<2 * Is>(t), std::get<2 * Is + 1>(t)}...);
    }
    
    template <typename C, typename ... Ts>
    C final_sum(const C& c0, const Ts&... ts)
    {
        static_assert(sizeof...(Ts) % 2 == 0);
        return sum_impl(c0, std::make_index_sequence<sizeof...(Ts) / 2>{}, std::tie(ts...));
    }
    

    std::index_sequence 是 C++14,但可以在 C++11 中实现。

    【讨论】:

    • 在函数 sum() 你有语法: result[i] += (cs[i] + ...);我相信这不是 C++11,是吗?这些还是一些好主意,谢谢
    • 确实是 C++17 实现。您可能会在 C++11/C++14 中得到类似的结果,但语法更冗长。
    • 添加了 C++14 版本。对于 C++11,我让你找到index_sequence 实现。
    • sum_implsum 可以合并为一个函数,只在 for 循环中包含 result[i] += ((std::get&lt;I * 2&gt;(t) * std::get&lt;I * 2 + 1&gt;(t)[i]) + ...);(C++17 变体),删除中间结构...
    • @Aconcagua:我认为拆分代码使它更清晰、更通用(我们可以有sum(c0, c1, c2, MulContainer{a3, c3}, ReverseContainer{c4});),但实际上,代码可以这样修改。
    猜你喜欢
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 2013-02-08
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2021-12-26
    • 1970-01-01
    相关资源
    最近更新 更多