【问题标题】:C++ functors, any effective aproach?C++仿函数,一种有效的方法?
【发布时间】:2020-06-14 11:34:41
【问题描述】:

在我的 C++ 代码中,我编写了两个函子,它们接受参数,一个返回总和,另一个返回减法,因此我可以将它们用作函数的参数。像这样:

template<class T>
class AddValues{
public:
    T operator()(const T &value1, const T &value2) {
            return value1 + value2;
    }
};

template<class T>
class SubstractValues{
public:
    T operator()(const T &value1, const T &value2) {
        return value1 - value2;
    }
};

但现在我想写 6 个仿函数,每个仿函数接受两个参数并返回真/假,第一个值是 &lt;,&lt;=,&gt;,&gt;=,==,!=,而不是另一个。

有没有比定义 6 个类更清晰的方法呢? 我正在使用 C++11

【问题讨论】:

  • 尝试使用 lambda。它们实际上是在替换 c++11 中的仿函数。
  • 应该已经定义了所有的仿函数。请参阅 std::plus、std::minus、std::less、std::greater、...。强烈建议重用那些反对重新定义它们。
  • 并且 lambdas 不会替换 C++11 中的仿函数。 Lambdas 可以使一些用例更容易,但适当的函子的好处是它们被命名。原始 lambda 有时比正确命名的仿函数更难理解,因为您必须检查代码才能了解它的实际作用。
  • @MikaelH 谢谢,但我想写我的,你能帮忙吗?
  • @MikaelH 出于好奇,您能否在这里展示如何使用 std::greater 和其他?

标签: c++ class templates generics functor


【解决方案1】:

注意:这篇文章是我对原帖的改进。

首先,您应该知道 STL 已经定义了一组函子。对于&lt;,&lt;=,&gt;,&gt;=,==,!=,请参见Comparators 下的https://en.cppreference.com/w/cpp/header/functional,对于+,-(您已重新定义)请参见算术运算。了解 STL 以及如何使用它是一种很好的做法。

如何使用它们

函子是与任何其他对象一样的对象,并且将与值语义一起使用。从功能上看,它们定义了函数运算符 (operator()),并且可以直接在对象上调用 ()。

std::less is_less;
bool is_0_less_than_0 = is_less(0,1); // Calls bool operator()(int, int) and evaluates to true

函子通常与算法结合使用。对于比较两个整数数组的不那么漂亮的用例:

std::array<int,4> low_numbers = {1,2,3,4};
std::array<int,4> high_numbers = {5,6,7,8};
std::array<bool,4> is_number_greater;
// compares low_numbers and high_numbers element wise and stores result in is_number_greater.
std::transform(low_numbers.begin(), 
    low_numbers_low.end(), 
    high_numbers.begin(), 
    is_number_greater.begin(),
    std::greater{}); 

如何编写自己的函子

所以您已经(功能方面)重新定义了 std::plus(作为 AddValues)和 std::minus(作为 SubtractValues)。请注意,我说的是功能方面的,因为 only 模板化函数运算符更加灵活:

struct AddValues{
    template<class T>
    T operator()(const T &value1, const T &value2) {
             return value1 + value2;
    }
};

并且由于成员方法operator()没有修改AddValues的任何成员,所以应该标记为const:

struct AddValues{
    template<class T>
    T operator()(const T &value1, const T &value2) const {
             return value1 + value2;
    }
};

那么在实例化对象的时候就不需要指定类型了。比较模板类:

AddValues<int> add_values; // templated type has to be explicitly written.
add_values(1,2); //=3

使用模板化方法:

AddValues add_values;
add_values(1,2); //=3, types deduced when calling method.

.

无论如何,您必须对&lt;,&lt;=,&gt;,&gt;=,==,!= 执行相同的操作,因为您需要一个围绕 每个 运算符的包装器。区别只是现在您返回布尔值而不是类型。

struct MyLess
{
    template<typename T>
    bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; }
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    相关资源
    最近更新 更多