在C++中封装大量参数14

Dan*_*iel 6 c++ oop encapsulation functional-programming c++14

我想写它使用许多参数,我将调用一个函数a,bc.我有四种在C++ 14中实现它的选择.

对于2018年的新现代C++项目,其中一种风格最符合ISO C++的理念?其他风格指南推荐哪些款式?

面向对象的风格

class Computer {
    int a, b, c;
public:
    Computer(int a, int b, int c) : a(a), b(b), c(c) {}
    int compute(int) const {
        // do something with a, b, c
    }
};
...
const Computer computer(a, b, c);
int result = computer.compute(123);
Run Code Online (Sandbox Code Playgroud)

优点:

  • 易于C++程序员掌握

缺点:

  • 要计算地图或折叠操作中的内容,我们必须做笨重的事情 [computer](int input){ return computer.compute(input); }

C风格

struct ComputeParams {
    int a, b, c;
};

int compute(const ComputeParams &params, int input) {
    // do something with params.a, params.b, params.c
}
...
const ComputeParams params{a, b, c};
int result = compute(params, 123);
Run Code Online (Sandbox Code Playgroud)

优点:

  • 易于C程序员掌握

缺点:

  • 详细的实现compute涉及调用params.a而不是a.
  • 详细调用,每次都必须传入一个结构.

Functor风格

struct Computor {
    int a, b, c;
    int operator()(int input) const {
        // do something with a, b, c
    }
};
...
const Computor compute{a, b, c};
int result = compute(123);
Run Code Online (Sandbox Code Playgroud)

优点:

  • 面向对象风格的所有优点,加上它看起来像一个函数
  • 可用于map,fold和for_each等功能操作

缺点:

  • "functor"这个词看起来很时髦.

功能风格

auto genCompute(int a, int b, int c) {
    return [a, b, c](int input) -> int {
        // do something with a, b, c
    }
}
...
auto compute = genCompute(a, b, c);
int result = compute(123);
Run Code Online (Sandbox Code Playgroud)

优点:

  • 易于OCaml程序员掌握
  • 可用于map,fold和for_each等功能操作
  • 技术上与仿函数相同

缺点:

  • 很难让C++和C程序员掌握
  • 由于lambda函数是由编译器生成的唯一类型,因此可能需要使用auto或模板魔术来内联lambda函数,或者std::function具有性能开销
  • 无法接受vtable的功能和多态性的继承

Ste*_*ell 2

其中很多内容都是基于观点的,但我会积极参与。

面向对象风格

不是你用的风扇。由于您支持的唯一操作是compute,因此它实际上operator ()具有不同的名称。 operator ()意味着您可以很好地使用algorithm标题,因此这是一个比函子和函数样式差的解决方案。

此外,使用此解决方案您的代码可能性能较差。如果您好奇的话,整个演讲值得一看,但 Chandler Carruth(LLVM/Clang 开发人员)解释了编译器如何看待您的代码(跳到大约 1:32:37,但整个演讲很棒)。其要点是,在此实现中您有一个隐式指针,并且指针/引用对于编译器来说更难优化。

C风格

不喜欢这个只是为了 API。您在缺点中提到,调用需要传递struct,而在使用需要操作单个事物(例如 中的所有内容algorithm)的库时,这是一个问题。您可以使用捕获您的 lambda 来解决这个问题struct,但那时我不知道您会得到什么。

功能风格

这就是我要走的路,也是我在工作中所推动的。我见过的示例表明,调用 lambda 函数并不比直接调用函数慢,因为编译器可以积极内联(它们知道确切的类型)。如果 C++ 程序员因为这种风格不同/新而难以适应,请告诉他们加快速度,因为它们落后于几个标准:)。

就最佳实践和社区正在使用的内容而言,Cppcon 中的示例似乎更适合函子/函数式风格。C++ 作为一种语言,看起来它确实总体上拥抱函数式设计。

  • 我使用 [Compiler Explorer](https://godbolt.org/) 快速查看了一下,“computer.compute(123);” 的代码与“compute(123);” 相同;相关的计算/lambda 函数也是如此。唯一的区别是调用构造函数和调用创建 lambda 或 default-ctor 结构的函数之间生成的代码中存在细微的调用约定差异。 (2认同)