I've managed to figure out how to use std::bind to replace a whole bunch of code that previously triggered C-style callbacks (not shown here) via a web of static variables, static functions, and a compiler extension __closure.
This code compiles and runs successfully; however, in trying to make a slight improvement I get a weird compiler error.
#include <iostream>
#include <string>
#include <functional>
typedef void MyFunc(std::string &);
struct Master
{
void func(std::string &s) { std::cout << "Master::func(" << s << ")\n"; }
void go();
Master() {}
private:
Master(Master const &);
};
int main()
{
Master m;
m.go();
}
void call_function( std::function<MyFunc> fp, std::string s )
{
fp(s);
}
template<typename FuncT, typename Host>
typename std::function<FuncT> my_binder(Host *h, FuncT Host::*p)
{
using std::placeholders::_1;
return std::bind(p, h, _1);
}
void Master::go()
{
std::string s("hello");
// OK
using std::placeholders::_1;
std::function<MyFunc> f = std::bind(&Master::func, this, _1);
call_function(f, s);
call_function( std::bind(&Master::func, this, _1), s );
// Undefined structure 'boost::function<void(std::string &)>'
my_binder(this, &Master::func);
// I'm hoping to end up here
// call_function( my_binder(this, &Master::func), s );
}
The code appears to work in latest g++ and clang, but gives
// Undefined structure 'boost::function<void(std::string &)>'
on another compiler which has not-quite-c++11 support. Is my code correct (i.e. the failing compiler has a bug)?
Also: is there a pre-existing template I can use instead of my_binder? My aim is to make it so that people can call call_function as easily as possible, without having to muck around with including std::placeholders and so on. Of course this is possible with a preprocessor macro but it'd be nice to use a template function.
Related
I'm trying to make a RenderClass where 1 function gets called from a Thread, which calculates everything and pushes the function calls to a vector while the other Thread calls a function of RenderClass which then calls every function that got pushed on the vector, is this even possible? also my code doesn't give me intellisense errors in vs just some weird C3867 error that doesn't make sense in my opinion when trying to compile.
I already tried playing around with the template function
like removing the RenderClass::*function to
template<typename Function, typename ...ARGS>
void QueueRenderFunction(Function *function, ARGS... args)
but can't get it to work.
here the whole testprogram I tested this on...
#include <Windows.h>
#include <iostream>
#include <functional>
#include <string>
#include <vector>
#include <mutex>
class Vector3 {
float x, y, z;
};
class RenderClass
{
public:
template<typename Function, typename ...ARGS>
void QueueRenderFunction(Function RenderClass::*function, ARGS... args)
{
_RenderList.push_back(std::forward<Function>(function, args...));
}
void CallRenderFunctions()
{
std::lock_guard<std::recursive_mutex> l(renderlist_mtx);
for (auto&& Function : RenderList)
Function();
}
//just as examplecode
void DRAWCIRCLE(Vector3 Position, float Range) {
std::cout << Range << std::endl;
}
void DRAWSTRING(Vector3 Position, std::string String) {
std::cout << String << std::endl;
}
void QueueDrawings() {
//begin new Renderlist
_RenderList.clear();
//some drawing calcs
//some Position
Vector3 Position;
QueueRenderFunction(DRAWCIRCLE, Position, 100.f);
QueueRenderFunction(DRAWSTRING, Position,"Name");
std::lock_guard<std::recursive_mutex> l(renderlist_mtx);
RenderList = _RenderList;
}
private:
std::recursive_mutex renderlist_mtx;
std::vector<std::function<void()>> RenderList;
std::vector<std::function<void()>> _RenderList;
};
RenderClass* Renderer = new RenderClass();
void Render() {
while (true)
{
Renderer->CallRenderFunctions();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int main() {
std::thread RenderThread(Render);
while (true)
{
Renderer->QueueDrawings();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return 0;
}
like said I get for example this error:
Severity Code Description Project File Line Suppression State
Error C3867 'RenderClass::DRAWCIRCLE': non-standard syntax; use '&' to create a pointer to member
and trying to &DRAWCIRCLE just then gives me
Error C2276 '&': illegal operation on bound member function expression
that's what makes me say it doesn't make sense in my opinion
Your problem is that you have a std::vector<std::function<void()>>, which is fine, but you need to add some augments. std::bind is your friend.
This code should do the trick.
template<typename Function, typename ...ARGS>
void QueueRenderFunction(Function function, ARGS... args)
{
_RenderList.push_back(std::bind(function, args...));
}
You probably also want to define the function you put into the render list as free from functions and pass what would have been this as argument.
As a side note, you probably want to use RenderList.swap(_RenderList); to reduce copying.
I want to bind a static member function to a boost::function using boost::bind. The following is an example of what I want to do (not working).
class Foo {
public:
static void DoStuff(int param)
{
// To do when calling back
}
};
class Question {
public:
void Setup()
{
AssignCallback(boost::bind(&Foo::DoStuff, _1)); // How to bind the static funciton here
}
void AssignCallback(boost::function<void(int param)> doStuffHandler)
{
...
...
}
};
I have previously used boost::bind with member functions using this syntax:
boost::bind(&Foo::NonStaticMember, this, _1, _2, _3, _4)
But this is obviously not correct for a static member.
Can you please explain to me how to correctly bind a static member function of a class using boost::bind?
It will be done as you do for normal functions binding.
For static function you just need to use its class name for to recognize the function by the compiler and skip the this argument since static finctions are bound to class not to the object.
Below is a simple example:
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
void test(boost::function<bool(int, int)> func)
{
std::cout<<"in test().\n";
bool ret = func(10, 20);
std::cout<<"Ret:"<<ret<<"\n";
}
class Test
{
public:
static bool test2(int a, int b)
{
std::cout<<"in test2().\n";
return a>b;
}
};
int main()
{
test(boost::bind(&Test::test2, _1, _2));
return 0;
}
O/P:
in test().
in test2().
Ret:0
You should not use this as static functions dont have this pointer.
int main()
{
test(boost::bind(&Test::test2, this, _1, _2));-----> Illegal
return 0;
}
Below error will occur:
techie#gateway1:myExperiments$ g++ boost_bind.cpp
boost_bind.cpp: In function âint main()â:
boost_bind.cpp:26: error: invalid use of âthisâ in non-member function
Hope this will help. :-)
Your code is correct. Maybe you experience some compiler issue? Can you cite the compilation output?
You can also try using std::function and std::bind instead. Only replace boost headers with "functional" header and write
std::placeholders::_1
instead of
_1
I want to have a class that can have a callback set to a pointer to member function. This means I need to store the address of the function, and the address of the object instance. The function should have the proper prototype and return value to what the callback expects.
I've played around with std::mem_fn and boost::bind (with the Boost Signals2 library), but it seems like I have to know the type of the class containing the callback function to store this information.
It seems like there should be a way to store a couple void* that would point to any object/function, but this obviously smells funny, loses type safety, etc.
Given a class SomeClass with a method some_method, I want to be able to do something like this:
SomeClass obj;
some_other_class.set_callback(&SomeClass::some_method, &obj);
Here is how I was able to accomplish this using Boost. Note that this uses Boost signals, and seems like overkill for a simple callback. Also, there is the issue of signals using "combiners" to determine the return value of the callback, since there are potentially multiple slots connected to a single signal. I only need support for a single callback. Also note that this is a complete compilable program:
#define _SCL_SECURE_NO_WARNINGS
#include <iostream>
#include <boost/bind.hpp>
#include <boost/signals2.hpp>
#include <string>
using namespace std;
struct MessageSource
{
boost::signals2::signal<void(const string &)> send_message;
typedef boost::signals2::signal<void(const string &)>::slot_type slot_type;
template<typename A, typename B>
boost::signals2::connection connect(A a, B b)
{
return send_message.connect(boost::bind(a, b, _1));
}
void send_msg(const string& msg)
{
send_message(msg);
}
};
struct Printer
{
void print(const string& msg) { std::cout << msg << std::endl; };
};
int main()
{
{
Printer p;
MessageSource s;
s.connect(&Printer::print, &p);
s.send_msg("test");
}
system("pause");
return 0;
}
I think the magic here is the fact that boost::bind() is able to handle a variety of types for its first argument. I just don't get how it can hold onto it in a private field of some sort without knowing the type...
Is this a case where a functor is really the right solution? It seems like member functions are so much more convenient to use...
Based on the comment by cdhowie above, I was able to come up with the following solution using std::function and std::bind:
#include <iostream>
#include <string>
#include <functional>
using namespace std;
struct MessageSource
{
function<void(const string& msg)> _callback;
template<typename A, typename B>
void connect(A func_ptr, B obj_ptr)
{
_callback = bind(func_ptr, obj_ptr, placeholders::_1);
}
void send_msg(const string& msg)
{
if (_callback)
_callback(msg);
}
void disconnect()
{
_callback = nullptr;
}
};
struct Printer
{
void print(const string& msg) { std::cout << msg << std::endl; };
};
int main()
{
{
Printer p;
MessageSource s;
s.connect(&Printer::print, &p);
s.send_msg("test");
s.disconnect();
s.send_msg("test again");
}
system("pause");
return 0;
}
I'm trying to figure out how I can switch between boost functions and c++11 functions depending on what the platform I'm compiling it on has available. I know that c++ doesn't have template aliasing (pre-c++11) so I wrote the following, but I can't understand the error message or why it's not working:
#define FUNCTION_Boost
#if defined(FUNCTION_Boost)
#include <boost/function.hpp>
#elif defined(FUNCTION_STL)
#include <functional>
#endif
template<typename Res, typename... ArgTypes>
struct function {
#if defined(FUNCTION_Boost)
typedef boost::function<Res(ArgTypes...)> type;
#elif defined(FUNCTION_STL)
typedef std::function<Res(ArgTypes...)> type;
#endif
};
// In instantiation of ‘function<void()>’:
// error: function returning a function
void foo(function<void ()>::type f) {
f();
}
// this works fine
void bar(boost::function<void ()> f) {
f();
}
no need to define one more function... everything could be done using using ;)
#define USE_BOOST_FUNCTION
#ifdef USE_BOOST_FUNCTION
# include <boost/function.hpp>
# define FUNCTION_NS boost
# else
# include <functional>
# define FUNCTION_NS std
# endif
#include <iostream>
namespace test {
using FUNCTION_NS::function;
}
int main()
{
test::function<void()> f = [](){ std::cout << __PRETTY_FUNCTION__ << std::endl; };
f();
return 0;
}
I have the impression that this code does not do what you think it does:
typename function<void ()>::type
binds "void ()" as Res just creating a function that returns a function.
what about:
...
void foo(typename function<void >::type f) {
f();
}
...
?
You can get something similar to the aliasing you are trying to get with boost::type_traits and boost::type_traits::function_traits specially. That said, I suspect that if you want a simple and portable solution, then the easiest to do is to use boost and wait for better times with C++ compilers and STL support for C++11.
typedef boost::function<void (int,bool)> MyCallback;
void RegisterCallback(MyCallback callback);
class A {
public:
void GoodCallback(int intArg,bool boolArg) {
printf("calling GoodCallback (%d,%s)\n",intArg,boolArg?"true":"false");
}
void BadCallback(int intArg) {
printf("calling BadCallback (%d)\n",intArg);
}
};
int TestFunction() {
A * myA=new A();
RegisterCallback(boost::bind(&A::GoodCallback,myA,_1,_2));
RegisterCallback(boost::bind(&A::BadCallback,myA,_1));
return 0;
}
Is there any way that I can make the second call to RegisterCallback not compile?
For context:
I recently changed the callback signature and added the bool argument. I thought I had updated everything that was using this, but I was mistaken. Other than renaming RegisterCallback everytime I change the signature, I would like to have a way to have the compiler enforce that all arguments are used.
The documentation says
Any extra arguments are silently ignored
It has to be this way in order to support _N placeholders. Witness:
void foo (int a, const char* b) {
std::cout << "called foo(" << a << "," << b << ")" << std::endl;
}
int main () {
boost::bind(foo,_1, _2)(1, "abc", foo, main, 2.0);
boost::bind(foo,_2, _5)(3.0, 2, foo, main, "def");
}
prints
called foo(1,abc)
called foo(2,def)
Any combination of arguments in the beginning, in the end or in the middle of the argument list can be ignored.
You need a simpler binder that doesn't support anything like _N placeholders. Boost doesn't seem to have one.
The problem isn't boost::function; the problem is that the function object boost::bind returns will take anything as parameters. Bind is, more or less, runtime defined, not compile-time defined. Therefore, the boost::bind object can be used with any boost::function.
[edit] OK, apparently boost::function is also a problem. But it's not the only problem.
You could always use std::function<...> instead.
The following does not compile on VS2010 SP1:
#include <functional>
void foo();
void bar(int);
int main()
{
std::function<void ()> f= std::bind(foo);
std::function<void ()> g= std::bind(bar); // does not match signature, does not compile.
return 0;
}
I'm a bit late with this answer but since the problem is the binding you could do this step later with the help of a templated version for your callback registration function and another one for regular function pointers:
template<typename C>
void RegisterCallback(void (C::* func)(int, bool), C* inst)
{
MyCallback callback(boost::bind(func, inst, _1,_2));
}
void RegisterCallback(void (*func)(int, bool))
{
MyCallback callback(func);
}
A * myA = new A();
RegisterCallback(&A::GoodCallback, myA);
RegisterCallback(&A::BadCallback, myA); // DOES NOT COMPILE
RegisterCallback(GoodCallback);
RegisterCallback(BadCallback); // DOES NOT COMPILE
This works as expected in VS2010 but has the disavantage of needing not one but two callback registration functions to correctly deal with member and non-member functions.
As another option you might have a look at the boost function_types library. It provides a parameter_types metafunction that extracts the parameter types of function pointers and returns them as a MPL sequence. Then with a bit template magic it's possible to validate the parameters of the callback function, something like:
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/mpl/equal.hpp>
using namespace boost;
using namespace boost::function_types;
template< typename Function >
void RegisterCallback(Function f)
{
BOOST_MPL_ASSERT((
mpl::equal<
parameter_types< Function >,
parameter_types< void(int,bool) >
>
));
MyCallback callback(f);
}
template<typename Function, typename T>
void RegisterCallback(Function f, T* inst)
{
BOOST_MPL_ASSERT((
mpl::equal<
parameter_types< Function >,
parameter_types< void (T::*)(int,bool) >
>
));
MyCallback callback(boost::bind(f, inst, _1, _2));
}
This also works as expected in VS2010 but you still need two function declarations although it should be possible to pack them in one if you define them inside a struct (and use a default template parameter argument for T);