callbacks fails when std::bind and std::function used - c++11

There are two class server and client. client calls method datas() on server. The server responds to the caller with the datalist using datacallback().
I see compile time error in function clientfun2 when serverobj.datas() is called. Please help to fix it.
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <vector>
enum Status { SUCCESS, FAILED, UNKOWN };
typedef std::vector<std::string> datalist;
class server {
public:
typedef std::function<void(int, Status, const datalist&)> Callback;
void datas(int request_id, Callback datacallback) {
datalist data; //here data is inserted and set to caller
std::cout << "Invoked datas method\n";
datacallback(123, SUCCESS, data); // sending back to caller
}
};
class client {
public:
void clientfun1(int req_id, Status status, datalist& datas) {
std::cout << "Invoked clientfun1\n";
}
void clientfun2(server serverobj) {
serverobj.datas(123,
std::bind(&client::clientfun1, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3)); /*Here the error comming pls help to fix */
}
};
int main() {
server serverobj;
client clientobj;
clientobj.clientfun2(serverobj);
}
****Error in text format****
bind.cc: In member function ‘void client::clientfun2(server)’:
bind.cc:30:76: error: no matching function for call to ‘server::datas(int, std::_Bind_helper<false, void (client::*)(int, Status, std::vector<std::__cxx11::basic_string<char> >&), client*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type)’
std::placeholders::_2, std::placeholders::_3));
^
bind.cc:14:8: note: candidate: void server::datas(int, server::Callback)
void datas(int request_id, Callback datacallback) {
^
bind.cc:14:8: note: no known conversion for argument 2 from ‘std::_Bind_helper<false, void (client::*)(int, Status, std::vector<std::__cxx11::basic_string<char> >&), client*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type {aka std::_Bind<std::_Mem_fn<void (client::*)(int, Status, std::vector<std::__cxx11::basic_string<char> >&)>(client*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>)>}’ to ‘server::Callback {aka std::function<void(int, Status, const std::vector<std::__cxx11::basic_string<char> >&)>}’

If we take the std::function and the actual function right next to each other it's easy to see a difference (reformatted to show it better):
// vvvvv
typedef std::function<void(int , Status , const datalist&)> Callback;
void clientfun1( int req_id, Status status, datalist& datas) {
// ^^^^^
Now we can see that for the std::function object the last argument is a reference to a constant datalist, while in the clientfun1 function it's not constant.
That makes the two function types different, leading to your error.

Related

Does 'this' pointer in bind C++ really matters?

I am trying to experiment bind in C++. Basically I have two class - Invokee. The invokee class registers a test handler that needs to be invoked upon some callbacks. The method here is -
void RegisterTestHandler(int id, TestFunction handler, std::string summary, std::string details);
Similarly, I have another method that actually invokes what has been registered -
void callHandler(int id);
Another class Test which has a function that needs to be invoked on callHandler.
unsigned int globalReset(int val);
In the main function, I am doing the nullptr for the second parameter in the bind. However, it still works and I don't get any crashes. Is it something working because of the compiler optimisation or undefined behaviour or it is something to do with bind concept.
Here is the entire experimental code.
// main.cpp
#include <iostream>
#include "test.h"
#include "invokee.h"
#include <memory>
#include <functional>
// beautify using clang-format in Vscode.
int main(int argc, char **argv)
{
auto *invokeTest = new Invokee();
Test *test = new Test();
std::string summary = "global reset summary";
std::string details = "global reset details";
//Basically there are two object from different class - InvokeTest --> does the registration of the handler.
// Now the InvokeTest has to call the member function of class object - Test.
// ?? How it can do - it can do using bind - basically, the this pointer of Test class is available to invokeTest
// therefore invokeTest can simply invoke the member function of test object.
// until the test point is valid, it can use it to invoke the method of it ?? --> Is it really correct?
delete(test); //experiment deleted the test pointer.
test= nullptr; // explicity set to nullptr
// still it works?? how come ??
invokeTest->RegisterTestHandler(1, std::bind(&Test::globalReset, test, std::placeholders::_1), summary, details);
invokeTest->callHandler(1);
return 0;
}
Here is the invokee.cpp -
#include "invokee.h"
void Invokee::RegisterTestHandler(int id, TestFunction handler, std::string summary, std::string details)
{
this->handlers[id] = handler;
this->summary[id] = summary;
this->details[id] = details;
}
void Invokee::callHandler(int id)
{
auto handler = handlers.find(id);
if (handler != handlers.end())
{
std::cout << "Found the handler --" << std::endl;
handler->second(1);
}
}
Here is the test.cpp
#include <iostream>
#include "test.h"
unsigned int Test::globalReset(int val)
{
std::cout << "global Reset invoked" << std::endl;
return 0;
}

C++ lambda callbacks

I am trying to make an HTTP class, and I want to use C++11 (not C++14 yet) callbacks via lambdas. I have 2 mockups available, the first one works... but looks ugly. The second one I am aiming, is not compiling (error at the end).
I cannot use std::function, as this is an embedded project, and that template generates a lot of code.
#include <cstring>
class HTTP
{
public:
void get1(const char* url, void* context, void (*callback)(void*, const char*) )
{
callback(context, "");
}
void get2(const char* url, void (*callback)(const char*) )
{
callback("");
}
};
void test()
{
int k;
HTTP http;
http.get1( "http://google.com", &k, [](void* context, const char* s){
int *k = (int*) context;
*k = strlen(s);
});
// this does not compile, looking for other alternatives
http.get2( "http://google.com", [&k](const char* s){
k = strlen(s);
});
}
Error from gcc (xtensa-esp32-elf-g++ (crosstool-NG crosstool-ng-1.22.0-80-g6c4433a) 5.2.0)
HttpRequests.cpp: In function 'void test()':
HttpRequests.cpp:29:6: error: no matching function for call to 'HTTP::get2(const char [18], test()::<lambda(const char*)>)'
});
^
HttpRequests.cpp:11:10: note: candidate: void HTTP::get2(const char*, void (*)(const char*))
void get2(const char* url, void (*callback)(const char*) )
^
HttpRequests.cpp:11:10: note: no known conversion for argument 2 from 'test()::<lambda(const char*)>' to 'void (*)(const char*)'
Lambdas without a capture list are compatible with function pointers, so your first lambda can be passed as an argument to get1(). However, lambdas with a capture list are not convertible to function pointers so it can not be passed to get2().
Lambdas with captures have state but functions can not have state, which is why such lambdas are not convertible to function pointers.
The most common way to have a function accept any lambda (or any callable object) is to use function templates:
class HTTP {
// ...
template <typename Callable>
void get1(const char* url, void* context, Callable callback)
{
callback(context, "");
}
template <typename Callable>
void get2(const char* url, Callable callback)
{
callback("");
}
}
Being function templates, code size might become an issue. If that's not acceptable, then keep your current functions and restrict yourself to never passing lambdas that use captures.

Passing a callable to a object that builds some kind of multi-index container

I'm trying to write a container that is able to categories objects and store pointers for which a categorisation function is true.
My problem is, that it does not compile and since I'm inexperienced in regard to callables like std::function or lambdas, I'm not sure how to fix it.
I want such a container, since I've the need to get some "Categories" often - and this makes it easy to cache the results. Especially if, in this example, the Dogs change their sound, the Categories can simply be recreated (since the callable is still there).
What is more, I'm interested in a solution that delivers good performance. As I read, std::functions are unlikely to be inlined. Is there a way to deliver inlined-performance?
The compiler says:
main.cpp: In function 'int main()':
main.cpp:51:108: error: no matching function for call to 'CategoryContainer<Dog>::addCategory(CategoryContainer<Dog>::Categories, main()::<lambda(auto:1&)>)'
dogs.addCategory( CategoryContainer<Dog>::Categories::Wuff, [](auto& d){return d.makeSound()=="Wuff";} );
main.cpp:39:10: note: candidate: void CategoryContainer<T>::addCategory(CategoryContainer<T>::Categories, std::function<bool()>) [with T = Dog]
void addCategory(Categories cat, std::function<bool()> f) {
main.cpp:39:10: note: no known conversion for argument 2 from 'main()::<lambda(auto:1&)>' to 'std::function<bool()>'
main.cpp: In lambda function:
main.cpp:52:71: error: expected '{' before '(' token
dogs.addCategory( CategoryContainer<Dog>::Categories::WauWau, []()(auto& d){return d.makeSound()=="WauWau";} );
main.cpp: In function 'int main()':
main.cpp:52:72: error: expected primary-expression before 'auto'
dogs.addCategory( CategoryContainer<Dog>::Categories::WauWau, []()(auto& d){return d.makeSound()=="WauWau";} );
And here is my code:
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <functional>
class Dog
{
public:
std::string makeSound() { return _sound; }
void setSound(std::string sound) { _sound=sound; }
private:
std::string _sound = "Wuff";
};
template<class T>
class CategoryContainer
{
public:
using objectContainer = std::vector<T>;
using pointerContainer = std::vector<T*>;
enum class Categories { Wuff, WauWau }; // Dogs are e.g. destinguished by the sound they make.
struct Category {
std::function<bool()> func;
pointerContainer pointers;
Category(std::function<bool()> f, objectContainer& data) : func(f) {
for(auto& i : data)
if( func(i) )
pointers.emplace_back(&i);
}
};
CategoryContainer(size_t n) {
data.resize(n); // Construct so many dogs.
}
void addCategory(Categories cat, std::function<bool()> f) {
indexed[cat] = Category(f, data);
}
private:
objectContainer data;
std::unordered_map<Categories, Category> indexed;
};
int main()
{
CategoryContainer<Dog> dogs(10);
dogs.addCategory( CategoryContainer<Dog>::Categories::Wuff, [](auto& d){return d.makeSound()=="Wuff";} );
dogs.addCategory( CategoryContainer<Dog>::Categories::WauWau, []()(auto& d){return d.makeSound()=="WauWau";} );
}
You pass [](auto& d){return d.makeSound()=="Wuff";} as a functor but addCategory is declared as
void addCategory(Categories cat, std::function<bool()> f) {
So the functor is expected to take zero arguments but actually takes Instead of one.std::function<bool()> you should use std::function<bool(const T&)>
As pointed by Alexey Guseynov (+1), your func() in Category receive a T object.
So, as suggested, should be std::function<bool(T const &)>.
And you have to correct this in three points:
1) std::function<bool()> func; become std::function<bool(T const &)> func;
2) Category(std::function<bool()> f, objectContainer& data) : func(f) become Category(std::function<bool(T const &)> f, objectContainer& data) : func(f)
3) void addCategory(Categories cat, std::function<bool()> f) become void addCategory(Categories cat, std::function<bool(T const &)> f).
But isn't enough.
Now the makeSound() method of Dog is used with const Dog instantiations inside your lambda funtions. So makeSound() (that doesn't modify the object) should be modified in a const method
std::string makeSound() const { return _sound; }
At this point I have some errors because Dogs is incompatible with std::unordered_map because (if I understand correctly) there isn't a specialization for std::hash<CategoryContainer<Dog>::Categories>
But, to avoid this problem, if you can change the
std::unordered_map<Categories, Category> indexed;
in a ordered std::map (adding #include <map> too)
std::map<Categories, Category> indexed;
and if you change, in addCategory(), the row
indexed[cat] = Category(f, data);
that give error for reasons (involving constructors) that I don't want investigate further, with
indexed.emplace(std::piecewise_construct,
std::forward_as_tuple(cat),
std::forward_as_tuple(f, data));
you shoul'd be able to compile your example.

Index with boost multi_index

How can I index a boost::multi_index container using a member function of class(that is being stored in the multi_index) that returns a constant reference of another class?
The error I get is :
error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'RetClass (__thiscall StoreMe::* )(void) const'
Edit1:
This is a complete verifiable piece of similar code I created which has the same error,
#include "stdafx.h"
#include<multi_index_container.hpp>
#include<boost/multi_index/hashed_index.hpp>
#include<boost/multi_index/mem_fun.hpp>
class RetClass
{
int a, b;
};
class StoreMe
{
RetClass ex;
public:
void setId(RetClass a) {
ex = a;
};
virtual const RetClass& getId() const { return ex; }
};
typedef boost::multi_index_container<
StoreMe,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<StoreMe, RetClass, &StoreMe::getId> >
>
> mi_storeMe;
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
TIA
-R
Use boost::multi_index::const_mem_fun.
Edited after OP's additional information: the return type specified in const_mem_fun has to be exactly the same as that of the function you want to use for indexing. Note the differences in your current code:
virtual const RetClass& getId() const;
const_mem_fun<StoreMe, RetClass, &StoreMe::getId>
So, change the const_mem_fun part as follows:
const_mem_fun<StoreMe, const RetClass&, &StoreMe::getId>

Bonjour DNS-SD callback not being called, where's a mistake in my code?

I'm trying to learn how to use Bonjour using this blog article as a reference:
http://marknelson.us/2011/10/25/dns-service-discovery-on-windows/
I've download sample project linked at the bottom of that page, it works like charm. Now I'm trying to reproduce service discovery from scratch in my console application:
#include <iostream>
#include <assert.h>
#include "dns/dns_sd.h"
class CDnsSd
{
public:
bool discoverAsync ();
private:
static void DNSSD_API onDiscoveryFinished (DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *serviceName, const char *regtype,
const char *replyDomain, void *context);
};
bool CDnsSd::discoverAsync()
{
DNSServiceRef client = NULL;
const DNSServiceErrorType err = DNSServiceBrowse( &client, 0, 0, ""_services._dns-sd._udp"", "", onDiscoveryFinished, this );
return err == kDNSServiceErr_NoError;
}
void DNSSD_API CDnsSd::onDiscoveryFinished( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context )
{
std::cout << __FUNCTION__;
}
void main ()
{
CDnsSd dnsSd;
const bool ret = dnsSd.discoverAsync();
assert(ret);
Sleep(10000000);
}
DNSServiceBrowse returns kDNSServiceErr_NoError, but the callback is never called. What's wrong?
You need a main loop processing Bonjour events. Look at the link you provided carefully. It's there in the "Driving the Callbacks" section.
I had to call the method named DNSServiceProcessResult to make it work for my part.
I hope it helped

Resources