C++怎么构建 key 是 string, value 是函数的 map

2018-02-20 16:17:29 +08:00
 fyyz

C++怎么构建 key 是 string,value 是函数的 map

网上查了下,用 std::function 可以表示一个函数对象,目前我写出来的类型是这样的:

std::map<
    std::string, 
    std::function<
        std::string(param_1&, param_1&)
    >
>
handle_map;

这样写对吗?

还有,这种 map 应该怎么 insert 数据进去啊,insert 的时候 std::function 对象是要用 std::bind 构造出来丢进去吗?

5137 次点击
所在节点    C
47 条回复
geelaw
2018-02-20 23:26:42 +08:00
@gnaggnoyil 我并没说过那是“类型”,而且并不需要第一个参数的类型是 param_1 且类别是左值,考虑第三个类型 T,若 T 有一个可以可以被访问的 operator param_1 & (),也是可以被接受的实参。
inflationaaron
2018-02-20 23:26:54 +08:00
@sinxccc 都 8102 年了还抱着 C89 不放,C++ 标准委员会要哭了。没有直接去掉特性是历史遗留问题,激进的语言早就废除了,只不过没有办法一刀切,但这不代表函数指针就是现代 C++ 的做法。我们要鼓励使用更好的解决方案。
inkedawn
2018-02-21 00:43:58 +08:00
新东西固然有学习成本,但是学完确实用着方便啊。
所谓的复杂,只是由于新东西有学习成本,又有已掌握的方案(虽然用起来麻烦些),而不想去了解新东西而已
TaoSama
2018-02-21 02:10:13 +08:00
看那些楼上的。。都 8012 年了+1。。
还在用 C99 甚至 C89。。赶紧学学 cpp11 和 cpp14 吧。
毕竟 cpp17 都这么久了 马上 cpp19 就来了。。
zmj1316
2018-02-21 08:27:52 +08:00
@TaoSama 下一个是 c++ 20 ......
linux40
2018-02-21 09:23:55 +08:00
comparator 难道不是必须
bool comp(const std::string &, const std::string &)
么,你传的啥比较器啊。
wwqgtxx
2018-02-21 09:36:01 +08:00
@linux40 人家传的是 value 的类型,不是 comparator 的
linux40
2018-02-21 09:36:49 +08:00
@wwqgtxx 对哈,眼花了。。。
gnaggnoyil
2018-02-21 09:57:12 +08:00
@geelaw 喷了……我竟然忘了这茬……好吧我现在算是明白标准里为啥动不动就出现"overload resolution"这个词了.这个词确实可以避免踩坑 233
coordinate
2018-02-21 10:08:18 +08:00
因为有的人用的编译器还是 vc6.0,所有他们不能接受 c++2.0,而且这类人还很多
RaynorGu
2018-02-21 10:35:17 +08:00
函数传个 lambda 就好了
liuminghao233
2018-02-21 11:12:57 +08:00
随手写了一个

```
#include <boost/unordered_map.hpp>
#include <boost/function.hpp>
#include <string>

void print666()
{
printf("666\n");
}

template<class T>
using UMAP = boost::unordered_map<std::string, boost::function<T()>>;

int main()
{
UMAP<void> umap;

umap.insert(UMAP<void>::value_type("666", boost::bind(print666)));

auto res = umap.find("666");

if (res != umap.end())
{
res->second();
}
}

```

这样写的话 value 只能是同款的 Function
TaoSama
2018-02-21 11:37:26 +08:00
@zmj1316 尴尬。。下一个标准这么远啊 垃圾语言毁我青春
p64381
2018-02-21 12:01:19 +08:00
我们石器时代的人这么写

typedef void (*CALL_BACK)(void*);
struct callback{
struct rb_node rb; // 用红黑树查找
// or
struct list_head lh; // 链表顺序查找
CALL_BACK cb;
char name[];
};

再或者用 hash 存 struct callback*, 然后 hash 查找
或者直接把 struct callback* 按照 name 排序存入数组, 然后二分查找 (本质和 rbtree 差不多)。

石器时代的人就这么几个简单粗暴的招式,使起来干净简单粗暴,出货也很快。
wizardforcel
2018-02-21 12:31:21 +08:00
@sinxccc 因为现代 C++ 不提倡 raw array 和 raw ptr。这也是为推动 C++ 发展做贡献。
bookit
2018-02-21 14:00:18 +08:00
不如用 C 来写,杜绝 C++
skadi
2018-02-21 14:39:34 +08:00
用 14 以上标准. lambda 封装.

std::map<string,function<void(void)>>mp;
mp["fuck"]=[/*some& or some=*/](){
//do something
}

或者你需要返回值,统一封装成 std::future

std::map<std::string, std::function<void(void)>>mp;

template<typename F,typename ...Args>
auto insert(std::string&& key,F&&f,Args&&...args)noexcept {
using r = std::invoke_result_t<F, Args...>;
auto task_pack_ptr = std::make_shared<std::packaged_task<r()>>([&]() -> r {
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
});
auto result = task_pack_ptr->get_future();
mp[std::forward<std::string>(key)] = [task_pack_ptr]() {
(*task_pack_ptr);
};
return result;
}
ipwx
2018-02-21 14:40:28 +08:00
@p64381 其实事情是这样的。如果只把函数指针替换成 std::function,当然没有比函数指针简单多少。std::function 和 lambda 表达式是一整套体系,会影响到你顶层的设计。你想想,如果你要把某个函数指针加上一些参数当做一个整体塞到 map 里面当 value,你用石器时代的招式是不是先要搞一整套铺垫?用上 std::function 和 lambda,通过闭包捕获局部参数,铺垫就都不需要了。你可以用更简洁的设计去做同样的事情。

如果你用过 scala (估计你没有用过),那你也许对 akka 这种 actor framework 有非常好的印象。没用过 actor,也许你用过 scala 的 future。又或者你没用过 scala,但是用过 nodejs,那你可能对回调也有印象。这三种新时代的并发程序设计方法,比线程池不知道高效到哪里去了,都强烈依赖局部闭包。所以 C++ 新特性对于新时代的并发程序还是很有帮助的。有一个库叫做 C++ Actor Framework,就走在路上。
skadi
2018-02-21 15:01:27 +08:00
撒币了... 应该是 (*task_pack_ptr)(); 才对...(逃
snnn
2018-02-21 15:02:18 +08:00
@bramblex
函数指针,是个很底层的东西。不管是什么操作系统,什么编译器,你可以很清楚的知道它编译成机器码是什么样子。而 std::function,是 C++标准库的一部分,不同的平台有不同的实现,而且调用栈巨复杂。
函数指针你按指传递就可以了,而 std::function 你还得考虑到底是传值,还是传引用,还是 move。函数指针你可以大胆的往 STL 容器里面放,怎么整都行。而 std::function 你就得三思了,搞不好取出来的就是空的了。

“ A callable type is a pointer to function, a pointer to member function, a pointer to member data, or a class type whose objects can appear immediately to the left of a function call operator.”
std::function 是对以上种种的统一封装,它的优势是以上种种都可以转成 std::function,这样传参的时候更通用。缺点是我们自己写代码的时候往往不需要这样过度的封装。我又不是要写一个 generic library 给所有人用,我干嘛要考虑那么多不同的情况。

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

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

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

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

© 2021 V2EX