我想知道是否可以从lambda表达式创建一个实际的functor对象。我不这么认为,但如果没有,为什么?
为了说明,给出下面的代码,使用x和y坐标的各种策略对点进行排序:
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>
struct Point
{
Point(int x, int y) : x(x), y(y) {}
int x, y;
};
template <class XOrder, class YOrder>
struct SortXY :
std::binary_function<const Point&, const Point&, bool>
{
bool operator()(const Point& lhs, const Point& rhs) const
{
if (XOrder()(lhs.x, rhs.x))
return true;
else if (XOrder()(rhs.x, lhs.x))
return false;
else
return YOrder()(lhs.y, rhs.y);
}
};
struct Ascending { bool operator()(int l, int r) const { return l<r; } };
struct Descending { bool operator()(int l, int r) const { return l>r; } };
int main()
{
// fill vector with data
std::vector<Point> pts;
pts.push_back(Point(10, 20));
pts.push_back(Point(20, 5));
pts.push_back(Point( 5, 0));
pts.push_back(Point(10, 30));
// sort array
std::sort(pts.begin(), pts.end(), SortXY<Descending, Ascending>());
// dump content
std::for_each(pts.begin(), pts.end(),
[](const Point& p)
{
std::cout << p.x << "," << p.y << "\n";
});
}
表达式std::sort(pts.begin(), pts.end(), SortXY<Descending, Ascending>());
根据x的下降值排序,然后按升序y值排序。这很容易理解,我不确定我是否真的想在这里使用lambda表达式。
但是如果我想用lambda表达式替换Ascending / Descending,你会怎么做?以下不有效:
std::sort(pts.begin(), pts.end(), SortXY<
[](int l, int r) { return l>r; },
[](int l, int r) { return l<r; }
>());
答案 0 :(得分:1)
出现此问题是因为SortXY只接受类型,而lambdas是对象。您需要重新编写它以便它需要对象,而不仅仅是类型。这是功能对象的基本用法 - 看看std::for_each
如何不采用类型,它需要一个对象。
答案 1 :(得分:0)
我发布了一个类似的问题w.r.t.类中的lambda仿函数。 看看这个,也许有帮助:
答案 2 :(得分:0)
我遇到了类似的问题:在某些情况下需要提供“原始”功能指针和其他仿函数。所以我想出了一个像这样的“解决方法”:
template<class T>
class Selector
{
public:
Selector(int (*theSelector)(T& l, T& r))
: selector(theSelector) {}
virtual int operator()(T& l, T& r) {
return selector(l, r);
}
int (*getRawSelector() const)(T&, T&) {
return this->selector;
}
private:
int(*selector)(T& l, T& r);
};
假设你有两个非常简单的函数 - 如上所述 - 是一个仿函数或一个像这样的原始函数指针:
int
findMinWithFunctor(int* array, int size, Selector<int> selector)
{
if (array && size > 0) {
int min = array[0];
for (int i = 0; i < size; i++) {
if (selector(array[i], min) < 0) {
min = array[i];
}
}
return min;
}
return -1;
}
int
findMinWithFunctionPointer(int* array, int size, int(*selector)(int&, int&))
{
if (array && size > 0) {
int min = array[0];
for (int i = 0; i < size; i++) {
if (selector(array[i], min) < 0) {
min = array[i];
}
}
return min;
}
return -1;
}
然后你可以这样称呼这个函数:
int numbers[3] = { 4, 2, 99 };
cout << "The min with functor is:" << findMinWithFunctor(numbers, 3, Selector<int>([](int& l, int& r) -> int {return (l > r ? 1 : (r > l ? -1 : 0)); })) << endl;
// or with the plain version
cout << "The min with raw fn-pointer is:" << findMinWithFunctionPointer(numbers, 3, Selector<int>([](int& l, int& r) -> int {return (l > r ? 1 : (r > l ? -1 : 0)); }).getRawSelector()) << endl;
当然在这个例子中没有真正的好处传递int作为参考...它只是一个例子: - )
改进:
您还可以将Selector类修改为更简洁:
template<class T>
class Selector
{
public:
typedef int(*selector_fn)(T& l, T& r);
Selector(selector_fn theSelector)
: selector(theSelector) {}
virtual int operator()(T& l, T& r) {
return selector(l, r);
}
selector_fn getRawSelector() {
return this->selector;
}
private:
selector_fn selector;
};
这里我们利用一个简单的 typedef 来定义函数指针一次,只使用它的名称,而不是一遍又一遍地写声明。