我想编写一个使用许多参数的函数,我将调用a
,b
和c
。我有四种在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);
[computer](int input){ return computer.compute(input); }
struct ComputeParams {
int a, b, c;
};
int compute(const ComputeParams ¶ms, int input) {
// do something with params.a, params.b, params.c
}
...
const ComputeParams params{a, b, c};
int result = compute(params, 123);
compute
的详细实施涉及致电params.a
而非a
。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);
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);
auto
或模板魔术来内联lambda函数,或std::function
具有性能开销{ LI>
答案 0 :(得分:4)
还有更多可以支持功能样式:您可以轻松地为某些参数值提供特殊/优化版本
std::function<int(int)> getCompute(int a, int b, int c)
{
if(a==0)
return [b,c](int input) { /* version for a=0 */ };
if(b==0)
return [a,c](int input) { /* version for b=0 */ };
if(c==0)
return [a,b](int input) { /* version for c=0 */ };
/* more optimized versions */
return [a,b,c](int input) { /* general version */ };
}
与其他选项相比,等效的东西并不简单。不幸的是,这需要使用std::function
来包装不同的lambda。
答案 1 :(得分:2)
其中很多都是基于意见的,但我会戴上帽子。
不适合您使用。由于您支持的唯一操作是compute
,因此它可以通过其他名称有效operator ()
。 operator ()
表示您可以很好地使用algorithm
标题,因此这是Functor和Functional样式的低级解决方案。
此外,您可能会使用此解决方案执行更差的代码。如果你感到好奇,整个谈话都值得关注,但Chandler Carruth(LLVM / Clang开发人员)explains how the compiler sees your code(跳到大约1:32:37,但整个演讲很棒)。它的要点是你在这个实现中有一个隐式指针,指针/引用对于编译器来说更难以优化。
仅仅为了API而不是粉丝。您在缺点中提到调用需要传递struct
,这对于处理需要单个操作的库(例如algorithm
中的所有内容)来说是一个问题。您可以使用捕获struct
的lambda来解决这个问题,但此时我不知道您获得了什么。
这就是我去的方式以及我在推动工作的方式。我已经看到的示例表明,调用lambda函数并不比直接调用函数慢,因为编译器可以积极地内联(他们知道确切的类型)。如果C ++程序员因为它的不同/新风格而挣扎于这种风格,请告诉他们加快速度,因为他们背后有几个标准:)。
就最佳实践和社区使用的内容而言,Cppcon的示例似乎更倾向于仿函数/功能风格。 C ++作为一种语言看起来像是一般的功能设计。
答案 2 :(得分:2)
tl; dr:使用下面的代码段。
它不是面向对象的,它只是将东西粘在物体上。用b和c&#34;做某事的功能。不应该是包含它们的对象的成员;该函数不是a,a b和c的组合所固有的。
与所谓的面向对象选项相似的批评。只是在没有充分理由的情况下在那里贴上一个仿函数。
你真的只是使用lambda而不是构造结构......并不可怕,但请看下一个选项:
这在C ++中非常流行。结构是一个非常好的对象 - 具有公共数据成员和默认构造函数和析构函数。
此外,您的利弊都可以轻松解决,代码更简单,更简单:
struct ComputeParams {
int a, b, c;
};
auto compute(ComputeParams params, int input) {
auto [a, b, c] = params;
// do something with a, b and c
}
auto result = compute(ComputeParams{a, b, c}, 123);
这是有效的C ++ 17(使用结构化绑定);在C ++ 14中,您需要std::tie
将参数绑定到本地名称。另外,请注意我在引用语义上使用了更多的值语义,让编译器发挥其魔力(它可能会发生;即使它对于少数int
来说并不重要)。
这是我推荐的。