求助大佬, Lambda 表达式可以直接转成 Functor 吗?

2019-08-21 22:33:04 +08:00
 sl0000

我想在 std::map 构造的时候直接使用 Lambda 表达式指定排序方式, 但是编译器报错了

class Person {
public:
    std::string name;
    int age;
    Person(const std::string & n , int a) {
        name = n;
        age = a;
    }
    class Compare {
    public:
        bool operator()(const Person & lhs, const Person & rhs) {
            return lhs.age < rhs.age;
        }
    };
};
    auto lambda = [](const Person & lhs, const Person & rhs){
        return lhs.age < rhs.age;
    };
    auto wapper = [lambda]() {
        return lambda;
    };


    bool a = Person::Compare()(Person("p1", 1), Person("p2", 2));
    bool b = wapper()(Person("p1", 1), Person("p2", 2));

    // Success
    std::set<Person, Person::Compare> sp; 

    // E: Template argument for template type parameter must be a type
    std::set<Person, wapper> sp; 



3084 次点击
所在节点    C
12 条回复
noli
2019-08-21 22:37:00 +08:00
std::bind
sl0000
2019-08-21 22:51:45 +08:00
@noli 请问需要怎么实现
ysc3839
2019-08-21 22:57:31 +08:00
std::set<Person, decltype(lambda)> sp(lambda);
noli
2019-08-21 23:03:45 +08:00
wisan
2019-08-21 23:05:09 +08:00
lambda 要用 std::move,不然不能拷贝。。更别说当参数了。。
noli
2019-08-21 23:06:17 +08:00
@ysc3839 #3

使用 std::function 代替 decltype<lambda> 是否更通用灵活一些?
ysc3839
2019-08-21 23:07:59 +08:00
@noli 我觉得不,因为还要多引入一个头文件。
geelaw
2019-08-21 23:11:27 +08:00
说得够明白了:代替 Person::Compare 的必须是一个类型,你的 wapper 不是一个类型,而是一个对象。

你可以这样

template <typename TElement, typename TCompare>
std::set<TElement, TCompare> make_set(TCompare &&cmp)
{
return {};
}

auto my_set = make_set<Person>([](Person const &a, Person const &b)
{
return a.age < b.age;
});
blinue
2019-08-21 23:25:18 +08:00
Compare 在 set 里被默认构造用于比较,lambda 对象的默认构造函数被删除,decltype(lambda)在 C++20 前行不通,只能定义新的类。在 C++20 里,不捕获的 lamda 对象的类型具有默认构造函数,就可以这样了:set<Person, decltype(lambda)>。
sl0000
2019-08-21 23:35:12 +08:00
@geelaw 这个编译不能通过呀, 提示
````
In file included from ~/Desktop/learnC++/LearnC++/main.cpp:11:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/set:458:19: error: no matching constructor for initialization of 'std::__1::set<Person, (lambda at ~/Desktop/learnC++/LearnC++/main.cpp:36:32), std::__1::allocator<Person> >::value_compare' (aka '(lambda at /Users/cosmojulis/Desktop/learnC++/LearnC++/main.cpp:36:32)')
: __tree_(value_compare()) {}
^
~/Desktop/learnC++/LearnC++/main.cpp:34:12: note: in instantiation of member function 'std::__1::set<Person, (lambda at ~/Desktop/learnC++/LearnC++/main.cpp:36:32), std::__1::allocator<Person> >::set' requested here
return {};
^
~/Desktop/learnC++/LearnC++/main.cpp:36:15: note: in instantiation of function template specialization 'make_set<Person, (lambda at ~/Desktop/learnC++/LearnC++/main.cpp:36:32)>' requested here
auto my_set = make_set<Person>([](const Person & a, const Person & b)
^
~/Desktop/learnC++/LearnC++/main.cpp:36:32: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
auto my_set = make_set<Person>([](const Person & a, const Person & b)
^
~/Desktop/learnC++/LearnC++/main.cpp:36:32: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
````
sl0000
2019-08-21 23:55:04 +08:00
感谢各位大佬, 今天学到特别多, 我睡了
geelaw
2019-08-22 00:42:15 +08:00
@sl0000 #10 Oops 你需要对 TCompare 删除 cv qualifiers 并且使用 std::forward。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/594008

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX