c++ 宏根据int模板值生成代码

5vf7fwbs  于 2023-05-08  发布在  其他
关注(0)|答案(3)|浏览(198)

我还在学习c++,并为它写了一个粒子模拟库。我想尽可能地优化我的工作代码,我的下一个瓶颈是我的向量运算符。
我创建了一个模板vector类,它依赖于vector中包含的类型和维度:

template<typename T, unsigned int D>
class Vector {
    private:
    T values[D];
}

我的操作符是这样定义的:

template<typename T, unsigned int D>
Vector<T, D> operator+(const Vector<T, D>& v1, const Vector<T, D>& v2) {
    T values [D];
    for(unsigned int i = 0; i < D; i++) {
        values[i] = v1[i] + v2[i];
    }
    return Vector<T, D>(values);
}

在我的模拟中,我最终做了很多向量计算,我想尝试优化它。
我的第一个假设是,如果我事先知道维度,我可以摆脱循环,得到这样的东西:

T values[3];
values[0] = v1[0] + v2[0];
values[1] = v1[1] + v2[1];
values[2] = v1[2] + v2[2];
return Vector<T, 3>(values);

所以我想到了一个递归宏,看起来像这样:

#define vec_sum(D, values, v1, v2) if D > 0 {
    vec_sum(D-1, values, v1, v2)
    values[D-1] = v1[D-1] + v2[D-1];
} else {
    values[0] = v1[0] + v2[0];
}

然后,我的函数看起来像这样:

template<typename T, unsigned int D>
Vector<T, D> operator+(const Vector<T, D>& v1, const Vector<T, D>& v2) {
    T values [D];
    vec_sum(D, values, v1, v2)
    return Vector<T, D>(values);
}

这样的代码生成可以用c++实现吗?

ssgvzors

ssgvzors1#

用手做是没有意义的。编译器可以将循环展开本身作为优化步骤。
在正确阅读生成的程序集和基准测试之后,如果您注意到编译器没有进行理想优化,则可以向循环添加编译器特定的属性,以通知编译器展开它。
展开是否有益也是不明显的,并且取决于确切的情况。如果您没有进行过基准测试,也没有更深入地了解您正在编译的架构/CPU,那么不要默认地认为它必须具有更高的性能。

hgb9j2n6

hgb9j2n62#

如果启用编译器优化,通常不会获得任何好处。
如果你想这样做,你可以在不使用宏的情况下使用一个助手函数std::index_sequence和一个折叠表达式(需要C++17):

template<typename T, unsigned int D>
class Vector {
private:
    T values[D];

    template<size_t ... Is>
    static constexpr Vector PlusImpl(Vector const& s1, Vector const& s2, std::index_sequence<Is...>)
    {
        Vector result;
        ((result.values[Is] = s1.values[Is] + s2.values[Is]), ...);
        return result;
    }

    friend constexpr Vector operator+(Vector const& s1, Vector const& s2)
    {
        return PlusImpl(s1, s2, std::make_index_sequence<D>());
    }
};
llycmphe

llycmphe3#

我建议你使用constexpr技术,并使vec_sum宏成为一个constexpr函数。
预处理器宏的第一个问题是,它在模板示例化之前展开。其次,宏不能递归地工作。这意味着,vec_sum(D-1, values, v1, v2)将无法工作,并且您的编译器很可能会抱怨您调用了未定义的函数vec_sum(D-1, values, v1, v2),或者抱怨缺少标记。

相关问题