在大型模板参数列表的情况下宏的便利性

Convenienve of macros in case of a large template argument list

在我的设计中,我有一个针对大量参数进行模板化的 class(假设为 Shell)。大多数这些参数是我在我的项目中定义的其他 classes,因为我为我的项目选择了基于策略的设计方法。

class 声明看起来像这样:

template <class int_t, class float_t, class Pol1, class Pol2,..., class PolN>
class Shell : Pol1, Pol2,...,PolN

前两个参数是应该使用的整型和浮点型。其余参数是项目中定义的特定策略。

这种设计对我来说很方便,因为它可以避免很多 运行 时间检查(我们的目标是 运行 时间性能)。然而,每当 he/she 想要创建 Shell class.

的实例时,键入一个包含 10 个以上参数的列表是非常混乱的(从用户的角度来看)

出于这个原因,我选择将这种打字负担与宏一起转移到一个单独的文件中。首先,我将所有策略默认为一个宏:

template <class int_t, class float_t, class Pol1 = DEF_1, class Pol2 = DEF_2,..., class PolN = DEF_N>
class Shell : Pol1, Pol2,...,PolN

模板参数可以作为宏在单独的文件中提供,而不是在求解器的声明中提供。例如:

#include <shell.cpp>

#define DEF_1 example1
#define DEF_2 example2
...
#define DEF_N exampleN

int main(){
    Shell<int,double> MyShell();
    return 0;
    }

这样,实例化class只需要传递给模板参数(其他+10个参数通过宏传递)。定义甚至可以移动到单独的文件中,如:

#include <shell.cpp>
#include "define.hpp"

这只是一种解决方法,这样就不必在每次创建 class 的实例时都提供 10 个以上的参数参数列表。宏是迄今为止我找到的最佳解决方案。但是,我知道在大多数 C++ 应用程序中宏不是 "recommended" 解决方案。

出于这个原因,我想知道这是否是一个典型的问题,没有宏如何解决它。我还想知道宏是否是 "ok" 解决方案,或者我是否应该不惜一切代价避免这种设计。我将不胜感激关于此主题的任何 help/comment,因为我对 C++ 还很陌生 :)

使用别名似乎更好:

template <class int_t, class float_t>
using MyShell = Shell<int_t, float_t, MyPol1, MyPol2, ..., MyPolN>;

这是一个完全无宏的解决方案,允许默认值和对默认策略的个别更改(无需重新指定默认值)并且应该不费吹灰之力进行扩展:

struct DefaultPol1 {};
struct DefaultPol2 {};
struct DefaultPol3 {};

struct OtherPol1 {};
struct OtherPol2 {};
struct OtherPol3 {};

template<class Pol1 = DefaultPol1, class Pol2 = DefaultPol2, class Pol3 = DefaultPol3>
struct Config
{
    using P1 = Pol1;
    using P2 = Pol2;
    using P3 = Pol3;


    template <class NewPol1>
    using ChangePol1To = Config<NewPol1, Pol2, Pol3>;

    template <class NewPol2>
    using ChangePol2To = Config<Pol1, NewPol2, Pol3>;

    template <class NewPol3>
    using ChangePol3To = Config<Pol1, Pol2, NewPol3>;
};

using DefaultConfig = Config<>;


template <class int_t, class float_t, class C = DefaultConfig>
class Shell : C::P1, C::P2, C::P3
{};


void foo()
{
    using config = DefaultConfig::ChangePol3To<OtherPol3>::ChangePol1To<OtherPol1>;
    Shell<unsigned, double, config> myShell;
}

https://godbolt.org/g/uPrRhc(改进版,感谢@Jarod42!)
(如果将空结构定义更改为仅(向前)声明,编译器错误表明选择了正确的策略)。

命名可能会随着上下文的增加而改进。