gpt4 book ai didi

c++ - 解决缺乏部分成员特化和特定性能设计约束的问题

转载 作者:行者123 更新时间:2023-11-30 05:09:42 29 4
gpt4 key购买 nike

在编写对性能敏感的数值模拟代码时,出现了一个设计问题,我花了几天时间思考,但找不到满意的解决方案。作为模拟的一部分,我有一个相当大的容器类模板,其部分特化包含与模拟的那部分相关的数据成员。然而,应用于该数据的转换可能千差万别,并通过许多不同的模板参数提供。这是我想到的那种行为的简化的最小玩具示例:

enum AlgType1 {Alg1Kind1, Alg1Kind2};
enum AlgType2 {Alg2Kind1, Alg2Kind2};
enum AlgType3 {Alg3Kind1, Alg3Kind2};

template<int D=2, AlgType1 T1=Alg1Kind2, AlgType2 T2=Alg2Kind1, AlgType3 T3=Alg3Kind1>
struct Grid {};

template<AlgType1 T1, AlgType2 T2, AlgType3 T3> // etc.
struct Grid<2, T1, T2, T3> {
const int N1, N2;
const SomeData d1, d2;
Grid(const GridParams params) : N1(params.N1), N2(params.N2), d1(params.d1), d2(d2) {}

template<AlgType T1>
SomeData AlgImplementation;
};

template<AlgType1 T1, AlgType2 T2, AlgType3 T3>
template<>
SomeData Grid<2,T1,T2,T3>::AlgImplementation<Alg1Kind1>() {
return d1*N1 + d2*N2; // just do something with the data in Grid
}

不幸的是,这种方法行不通,因为即使是完全显式的成员模板特化也是不允许的,除非类模板也是完全特化的。在我的例子中,这意味着明确说明我编写的所有不同算法类型的所有可能组合,因此这不是一个选项。如果我可以将传统的运行时多态性与虚函数一起使用,那么这个问题将是微不足道的,但是性能开销是我无法承受的(是的,我已经对其进行了基准测试,这很重要)。到目前为止,我尝试过的简单模板替代方案要么无法扩展(就代码膨胀而言),因为添加了更多算法和更多种类的算法(如传统 CRTP 的情况),要么它们自身存在重大问题。

到目前为止,我发现的最不坏的解决方案涉及算法的简单的基于策略的设计实现,以及用于实际工作的静态成员函数。但是,这将算法实现与 Grid 类的主要范围分离,因此我必须通过每个变量传递数据,或者使用类似以下内容传递指向相关 Grid 实例的指针:

template<class Grid, AlgType1 T1> class Alg1Policy {};
template<class Grid> class Alg1Policy<Alg1Kind1> {
static SomeData run(Grid grid) {
return grid->d1*grid->N1 + grid->d2*grid->N2;
}
}
// and then in the partially specialized Grid class, the last two lines change to:
SomeData AlgImplementation() {
return Alg1Policy<decltype(this),T1>::run(this);
}

无论哪种方式,我都会招致无法完全减轻的相当大的语法开销,以及在后一种情况下追逐一些额外的指针。因此,我对这个解决方案不满意。我还考虑了其​​他一些选项,包括 enable_if 和类似的构造,但是随着算法数量的增加,这些方法的复杂性增长得太快了。请注意,尽管这里的示例很简单,但我也有算法特化,这些特化依赖于同时具有特定值组合的两个或更多不同的模板参数。

这里的基本问题是,我希望将我的数据保留在与我通常从组件(策略、特征或其他构造)组装的行为相同的范围内,以减少样板文件并避免不必要的性能成本。在没有语言支持偏成员特化的情况下,有没有更好的办法我没有想到?或者我是否以完全错误的方式思考这个问题?

最佳答案

您可以雇用 SFINAE “专门化”您的成员函数。

#include <type_traits>

enum AlgType1 {Alg1Kind1, Alg1Kind2};
enum AlgType2 {Alg2Kind1, Alg2Kind2};
enum AlgType3 {Alg3Kind1, Alg3Kind2};

template<int D=2, AlgType1 T1=Alg1Kind2, AlgType2 T2=Alg2Kind1, AlgType3 T3=Alg3Kind1>
struct Grid {};

template<AlgType1 T1, AlgType2 T2, AlgType3 T3> // etc.
struct Grid<2, T1, T2, T3> {
const int N1, N2;
const SomeData D1, D2;
Grid(const GridParams params) : N1(params.N1), N2(params.N2), D1(params.d1), D2(params.d2) {}

template<AlgType1 Ta>
std::enable_if_t<Ta==Alg1Kind1,SomeData> AlgImplementation()
{ return D1*N1 + D2*N2; }

template<AlgType1 Ta>
std::enable_if_t<Ta==Alg1Kind2,SomeData> AlgImplementation()
{ return D1*N1 - D2*N2; }
};

请注意,您可以以不同方式应用 SFINAE,例如根据参数的类型

    template<AlgType1 Ta>
SomeData AlgImplementation(std::enable_if_t<Ta==Alg1Kind2>* =nullptr);

或第二个模板参数

    template<AlgType1 Ta, typename E=std::enable_if_t<Ta==Alg1Kind2>>
SomeData AlgImplementation();

等等

顺便问一下,您正在实现哪种算法? (我只是好奇)。

关于c++ - 解决缺乏部分成员特化和特定性能设计约束的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46027956/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com