繁体   English   中英

为什么我应该更喜欢单独的 function 而不是 static 方法在 c++ 中进行函数式编程?

[英]Why should I prefer a separate function over a static method for functional programming in c++?

在我的另一个问题中, 如何使用 static 方法作为 c++ 中的回调,人们解决了我的实际问题,然后建议我采取不同的方法来遵循最佳实践。 我想更好地理解为什么。

这个例子使用了一个比较器,但我真的很想了解函数式编程是否有一般规则(例如,也许还有与 class 等相关的聚合器函数)

比较器 function 的示例用例:

#include <set>

int main() {
    std::set<MyClass, decltype(SOMETHING_HERE)> s(SOMETHING_HERE);
    return 0;
}

以下是我知道的解决方案,从最推荐到最不推荐(我相信) - 与我目前选择的顺序相反。

1.

使用仿函数的推荐方式(我相信):

struct MyComparator {
    bool operator() (MyClass a, MyClass b) const {
        return a > b; // Reversed
    }
};
std::set<MyClass, MyComparator)> s;

我不喜欢:冗长; 在词汇上与 MyClass 无关; 我不明白为什么 s 没有构造函数参数。 我对缺少参数感到困惑,因为set似乎在编译时/与类型系统(如本例中)以及在运行时/与指针混合/组合决定比较算法。 如果这只是一种或另一种方式,我会接受“就是这样”。

2.

一种对我来说似乎更好的方法:

auto const my_comparator = [](int a, int b) {
    return a > b;
};
std::set<int, decltype(my_comparator)> s(my_comparator);

它更简洁。 意图很明确:它是 function,而不是可能添加到的 class。 传递 object,而不仅仅是类型,对我来说是有意义的(不可能有 2 种不同的实现)。

3.

对我来说最有意义的方法(基于其他语言):

class MyClass {
public:
    
    // More code here
    
    static auto compare_reverse(MyClass a, MyClass b) {
        return a > b;
    }
};
std::set<int, decltype(&MyClass::compare_reverse)> s(&MyClass::compare_reverse);

它显然与 MyClass 相关(并且在词法上与之相关)。 似乎有效(尽管有人告诉我不是)而且简洁。


任何解释为什么推荐的顺序更好,性能,错误/可维护性,哲学,非常感谢。

首先,请注意,如果您只想要一个>比较器,则有std::greater<>std::greater<MyClass>前者通常是优越的)。


查看您列出的选项:

(1)

struct MyComparator
{
    bool operator()(MyClass a, MyClass b) const
    {
        return a > b;
    }
};
std::set<MyClass, MyComparator)> s;

正如你所说,这是推荐的方式。

与 MyClass 没有词法关联

正如评论中所建议的,您可以将它放在MyClass中。

不明白为什么 s 没有构造函数参数

如果您不将比较器传递给构造函数,则比较器是默认构造的(如果它是默认构造的,否则会出现编译错误)。

您可以手动传递MyComparator{} ,但没有意义。

(2)

auto my_comparator = [](int a, int b)
{
    return a > b;
};
std::set<int, decltype(my_comparator)> s(my_comparator);

它完全等同于 (1),除了您被迫将my_comparator传递给构造函数。 C++20 通过使 lambdas 默认可构造(如果它们没有捕获)来解决此问题,从而使参数变得不必要。

(3)

class MyClass
{
  public:
    static auto compare_reverse(MyClass a, MyClass b)
    {
        return a > b;
    }
};
std::set<int, decltype(&MyClass::compare_reverse)> s(&MyClass::compare_reverse);

这为您提供了一个额外的功能:您可以在运行时通过将不同的函数传递给构造函数来选择比较器。

这种能力带来了开销:该集合存储了一个指向 function 的指针(通常为 4 或 8 个字节),并且在进行比较时必须查看该指针。

(3.5)

您可以将 function 包装在std::integral_constant中。 结果等价于(1)。

bool foo(int x, int y) {return x > y;}

std::set<int, std::integral_constant<decltype(&foo), foo>> s;
// Or:
using MyComparator = std::integral_constant<decltype(&foo), foo>;
std::set<int, MyComparator> s;

如果您正在处理现有类型,这很好,它将比较器提供为 function,并且您不想要 (3) 的开销。


所有这些(除了(3))都是等价的。

如果std::greater<>适用,则应使用它。

否则,我会推荐 (1) 作为最不容易混淆的选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM