CC_CALLBACK的含义,以及与std:bind之间的关系

转载自sta特530:http://blog.csdn.net/start530/article/details/21245565

本篇的主题就是揭露CC_CALLBACK 与 std::bind之间不可告人的秘密......

首先看一段代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //先是创建3个精灵  
  2. boy = Sprite::create("boy.png");//创建boy  
  3. boy->setPosition(Point(visibleSize.width/2,visibleSize.height/2));  
  4. this->addChild(boy,1);  
  5.   
  6. girl_1 = Sprite::create("girl_1.png");//创建girl1  
  7. girl_1->setPosition(Point(visibleSize.width/3,visibleSize.height/2));  
  8. girl_1->setTag(10);  
  9. this->addChild(girl_1,1);  
  10.   
  11. girl_2 = Sprite::create("girl_3.png");//创建girl2  
  12. girl_2->setPosition(Point(2*visibleSize.width/3,visibleSize.height/2));  
  13. girl_2->setTag(20);  
  14. this->addChild(girl_2,1);  
  15.   
  16. //让boy运动,通过Callfunc回调到callback1  
  17. boy->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,100)),  
  18.                                     CallFunc::create(CC_CALLBACK_0(HelloWorld::callback1,this)),  
  19.                                     NULL));  
三个回调函数的实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void HelloWorld::callback1()  
  2. {  
  3.     CCLOG("in callback1");  
  4.     //girl1运动,最后回调到callback2  
  5.     girl_1->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,150)),  
  6.                                             CallFunc::create(CC_CALLBACK_0(HelloWorld::callback2,this,girl_1)),  
  7.                                             NULL));  
  8. }  
  9. void HelloWorld::callback2(Node* sender)  
  10. {  
  11.     //girl2运动,最后回调到callback3  
  12.     girl_2->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,200)),  
  13.         CallFunc::create(CC_CALLBACK_0(HelloWorld::callback3,this,girl_2,99)),  
  14.         NULL));  
  15.   
  16.     CCLOG("in callback2,sender tag is:%d",(Sprite*)sender->getTag());  
  17. }  
  18. void HelloWorld::callback3(Node* sender, long data)  
  19. {  
  20.     //最终输出  
  21.     CCLOG("in callback3,everything is OK,sender tag is:%d,date is:%ld",(Sprite*)sender->getTag(),data);  
  22.     CCLOG("girl2 dandan ask:what fake the CC_CALLBACK is?");  
  23. }  

整个过程就是boy“勾引”girl1,但girl1显然对异性兴趣不大,于是她也勾引girl2......可是,girl2对同性异性都没兴趣,她只是淡淡的说了句:CC_CALLBACK到底是什么?调试如图:


好吧,先让我回口血,然后再来回答girl2的问题:CC_CALLBACK到底是什么碗糕(东东)?
我们先进CC_CALLBACK源码里看看:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // new callbacks based on C++11  
  2. #define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)  
  3. #define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)  
  4. #define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)  
  5. #define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 ##__VA_ARGS__)  
看完后恍然大悟!不看不知道,一看...和没看一样...
这里主要注意两点:一是 std::bind,二是##_VA_ARGS_; ##_VA_ARGS_是可变参数宏
,我就不多说了。 重点讲的是std::bind。
std::bind是在C++ 11里新加入的成员。可以将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表.
调用bind的一般形式为:
auto newCallback = bind(callback,arg_list);
其中,newCallback是一个可调用对象,arg_list是可以用逗号分隔的参数列表,至于是啥参数,那就看callback函数里有啥参数啦。也就是说,当我们调用newCallback时,newCallback会调用函数callback,并传递参数arg_list给callback.

看完上面的内容你的理解可能还比较模糊,那直接来个例子:有一个函数callback,如下,

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int callback(int one,char two,double three);  
下面我们用bind来调用callback

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. auto newCallback = bind(callback,_1,_2,1.5);  
  2. int x = newCallback(10,'h');  //这句相当于:int x = callback(10,'h',1.5);  
“_1″是一个占位符对象,用于表示当函数callback通过函数newCallback进行调用时,函数newCallback的第一个参数在函数callback的参数列表中的位置。第一个参数称为”_1″, 第二个参数为”_2″,依此类推,有意思吧。至于‘1.5’是指默认参数,它处于_1和_2的后面,所以它就是double类型的参数了.
在强调一点就是:_1这类占位符都定义在一个名为placeholders的命名空间中,而这个命名空间本身定义在std的命名空间中。为了使用这些名字,两个命名空间都要写上,
如:

std::placeholders::_1;

这样编写贼麻烦,所以在要使用_1时,可以加上这么一句:
using namespace namespace_name; 恩,ok

恩,bind就介绍到这,讲的比较浅,不理解的可以百度研究下。最后再回过头来看下CC_CALLBACK的定义,是不是清晰多了?
最后在举个例子吧,还是之前的boy,girl1,girl2,只是他们之间传递“爱意”的方式要换下了。不用CC_CALLBACK,改用std::bind。代码如下 :

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //让boy运动,通过Callfunc回调到callback1  
  2. boy->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,100)),  
  3.                                     CallFunc::create(std::bind(&HelloWorld::callback1,this)),  
  4.                                     NULL));  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void HelloWorld::callback1()  
  2. {  
  3.     CCLOG("in callback1");  
  4.     //girl1运动,最后回调到callback2  
  5.     girl_1->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,150)),  
  6.                                             CallFunc::create(std::bind(&HelloWorld::callback2,this,girl_1)),  
  7.                                             NULL));  
  8.     CCLOG("boy ask girl_1:can you do my girlFriends?");  
  9. }  
  10. void HelloWorld::callback2(Node* sender)  
  11. {  
  12.     //girl2运动,最后回调到callback3  
  13.     girl_2->runAction(CCSequence::create(MoveBy::create(1.0f,Point(0,200)),  
  14.         CallFunc::create(std::bind(&HelloWorld::callback3,this,girl_1,99)),  
  15.         NULL));  
  16.   
  17.     CCLOG("in callback2,sender tag is:%d",(Sprite*)sender->getTag());  
  18.     CCLOG("girl_1 ask girl_2:I love girl_2");  
  19. }  
  20. void HelloWorld::callback3(Node* sender, long data)  
  21. {  
  22.     //最终输出  
  23.     CCLOG("in callback3,everything is OK,sender tag is:%d,date is:%ld",(Sprite*)sender->getTag(),data);  
  24.     CCLOG("girl2 dandan say:I know how to use CC_CALLBACK!");  
  25. }     


恩,就是这样子了。bind与CC_CALLBACK之间的关系就是这么的...简单。


尊重原创,转载请注定来自star特530:http://blog.csdn.net/start530/article/details/21245565

<think>好的,我现在要解决用户提供的这个C++编译错误。错误信息是“no matching function for call to ‘picture_show::image_callback()’”,发生在show.cpp文件的第14行第109列。看起来是在创建订阅的时候,绑定回调函数出了问题。 首先,我需要理解错误的原因。这个错误通常发生在尝试将成员函数作为回调函数绑定时,但参数不匹配或者语法不正确。用户使用的代码是ROS 2中的create_subscription方法,回调函数通过std::bind来绑定。 让我看一下用户提供的代码片段: subscription_ = create_subscription<sensor_msgs::msg::Image>( "image_raw", 10, std::bind(&picture_show::image_callback(), this, std::placeholders::_1)); 这里有几个可能的问题点。首先,std::bind的第一个参数是成员函数的地址,但用户在这里写成了&picture_show::image_callback(),这实际上是调用了image_callback函数并取其地址,而不是传递函数指针本身。正确的写法应该是去掉括号,即&picture_show::image_callback。 其次,成员函数作为回调时,std::bind需要正确的参数占位符。image_callback应该有一个参数,比如const sensor_msgs::msg::Image::SharedPtr msg。因此,在绑定的时候,应该只使用一个占位符_1,但用户可能在这里的std::bind参数顺序有误。 正确的std::bind结构应该是将成员函数指针作为第一个参数,然后是this指针,接着是占位符。所以应该是std::bind(&picture_show::image_callback, this, std::placeholders::_1)。 另外,还需要确认image_callback的函数签名是否正确。例如,它应该声明为void image_callback(const sensor_msgs::msg::Image::SharedPtr msg),并且是类的成员函数,可能有const修饰符,取决于上下文。 总结可能的问题点: 1. 在绑定成员函数时错误地加上了括号,导致取函数调用结果的地址而非函数指针。 2. std::bind的参数顺序不正确,应该先传递成员函数指针,再传递this,再占位符。 3. 回调函数的参数是否create_subscription预期的匹配,例如参数类型是否正确。 修改后的代码应该是: subscription_ = create_subscription<sensor_msgs::msg::Image>( "image_raw", 10, std::bind(&picture_show::image_callback, this, std::placeholders::_1)); 同时,检查image_callback的声明是否std::function<void(const sensor_msgs::msg::Image::SharedPtr)>匹配,即参数类型是否正确,以及是否为类的非静态成员函数。 可能用户还有其他问题,比如没有正确包含头文件,或者在类picture_show中没有正确声明image_callback为public成员函数,但这些可能性需要用户进一步检查。但根据当前的错误信息,最可能的是std::bind的使用错误。</think>在ROS 2中创建订阅时出现`no matching function`错误,通常是由于回调函数绑定方式不正确导致的。以下是分步解决方案: --- ### **错误原因分析** ```cpp std::bind(&picture_show::image_callback(), this, std::placeholders::_1) // ▲ 错误点:多写了括号() ▲ 参数顺序错误 ``` 1. **成员函数指针语法错误** `&picture_show::image_callback()`的写法会尝试调用函数并取地址,而实际需要的是成员函数指针(应去掉括号)。 2. **std::bind参数顺序错误** 成员函数绑定的正确顺序应为:`函数指针 -> 对象指针 -> 占位符参数` 3. **回调函数签名不匹配** Image订阅要求回调函数接收`const sensor_msgs::msg::Image::SharedPtr`类型参数 --- ### **解决方案** #### 步骤1:修正函数指针语法 ```cpp // 原错误写法 &picture_show::image_callback() // 修正为(去掉括号) &picture_show::image_callback ``` #### 步骤2:调整std::bind参数顺序 ```cpp // 正确绑定格式 std::bind(成员函数指针, 对象指针, 占位符参数) ``` #### 步骤3:验证回调函数签名 确保类成员函数声明为: ```cpp void image_callback(const sensor_msgs::msg::Image::SharedPtr msg); ``` #### 最终修正代码 ```cpp subscription_ = create_subscription<sensor_msgs::msg::Image>( "image_raw", 10, std::bind(&picture_show::image_callback, // 成员函数指针 this, // 对象指针 std::placeholders::_1)); // 占位符参数 ``` --- ### **补充检查** 1. 类声明中`image_callback`必须是`public`成员函数 2. 确保包含必要的头文件: ```cpp #include <sensor_msgs/msg/image.hpp> ``` 3. 如果使用C++17或更高版本,可改用lambda表达式更简洁: ```cpp subscription_ = create_subscription<sensor_msgs::msg::Image>( "image_raw", 10, [this](const sensor_msgs::msg::Image::SharedPtr msg) { this->image_callback(msg); }); ``` --- ### **技术原理** - `std::bind`需要为成员函数绑定对象实例(`this`指针) - ROS 2订阅机制要求回调函数严格匹配消息类型 - 占位符`_1`表示第一个参数(即收到的Image消息) 修改后应能正常编译,若仍有问题,请检查类定义是否完整包含`image_callback`声明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值