I am currently working with Boost.Python and would like some help to solve a tricky problem.
Context
When a C++ method/function is exposed to Python, it needs to release the GIL (Global Interpreter Lock) to let other threads use the interpreter. This way, when the python code calls a C++ function, the interpreter can be used by other threads.
For now, each C++ function looks like this:
// module.cpp
int myfunction(std::string question)
{
ReleaseGIL unlockGIL;
return 42;
}
To pass it to boost python, I do:
// python_exposure.cpp
BOOST_PYTHON_MODULE(PythonModule)
{
def("myfunction", &myfunction);
}
Problem
This scheme works fine, however it implies that module.cpp depends on Boost.Python for no good reason. Ideally, only python_exposure.cpp should depend on Boost.Python.
Solution?
My idea was to play with Boost.Function to wrap the function calls like this:
// python_exposure.cpp
BOOST_PYTHON_MODULE(PythonModule)
{
def("myfunction", wrap(&myfunction));
}
Here wrap would be in charge of unlocking the GIL during the call to myfunction. The problem with this method is that wrap needs to have the same signature as myfunction which would pretty much mean re-implementing Boost.Function...
I would be very thankful if someone had any suggestion to this problem.
Exposing functors as methods is not officially supported. The supported approach would be to expose a non-member function that delegates to the member-function. However, this can result in a large amount of boilerplate code.
As best as I can tell, Boost.Python's implementation does not explicitly preclude functors, as it allows for instances of python::object to be exposed as a method. However, Boost.Python does place some requirements on the type of object being exposed as a method:
The functor is CopyConstructible.
The functor is callable. I.e. instance o can be called o(a1, a2, a3).
The call signature must be available as meta-data during runtime. Boost.Python calls the boost::python::detail::get_signature() function to obtain this meta-data. The meta-data is used internally to setup proper invocation, as well as for dispatching from Python to C++.
The latter requirement is where it gets complex. For some reason that is not immediately clear to me, Boost.Python invokes get_signature() through a qualified-id, preventing argument dependent lookup. Therefore, all candidates for get_signature() must be declared before the calling template's definition context. For example, the only overloads for get_signature() that are considered are those declared before the definition of templates that invoke it, such as class_, def(), and make_function(). To account for this behavior, when enabling a functor in Boost.Python, one must provide a get_signature() overload prior to including Boost.Python or explicitly provide a meta-sequence representing the signature to make_function().
Lets work through some examples of enabling functor support, as well as providing functors that support guards. I have opted to not use C++11 features. As such, there will be some boilerplate code that could be reduced with variadic templates. Additionally, all of the examples will use the same model that provides two non-member functions and a spam class that has two member-functions:
/// #brief Mockup class with member functions.
class spam
{
public:
void action()
{
std::cout << "spam::action()" << std::endl;
}
int times_two(int x)
{
std::cout << "spam::times_two()" << std::endl;
return 2 * x;
}
};
// Mockup non-member functions.
void action()
{
std::cout << "action()" << std::endl;
}
int times_two(int x)
{
std::cout << "times_two()" << std::endl;
return 2 * x;
}
Enabling boost::function
When using the preferred syntax for Boost.Function, decomposing the signature into meta-data that meets Boost.Python requirements can be done with Boost.FunctionTypes. Here is a complete example enabling boost::function functors to be exposed as a Boost.Python method:
#include <iostream>
#include <boost/function.hpp>
#include <boost/function_types/components.hpp>
namespace boost {
namespace python {
namespace detail {
// get_signature overloads must be declared before including
// boost/python.hpp. The declaration must be visible at the
// point of definition of various Boost.Python templates during
// the first phase of two phase lookup. Boost.Python invokes the
// get_signature function via qualified-id, thus ADL is disabled.
/// #brief Get the signature of a boost::function.
template <typename Signature>
inline typename boost::function_types::components<Signature>::type
get_signature(boost::function<Signature>&, void* = 0)
{
return typename boost::function_types::components<Signature>::type();
}
} // namespace detail
} // namespace python
} // namespace boost
#include <boost/python.hpp>
/// #brief Mockup class with member functions.
class spam
{
public:
void action()
{
std::cout << "spam::action()" << std::endl;
}
int times_two(int x)
{
std::cout << "spam::times_two()" << std::endl;
return 2 * x;
}
};
// Mockup non-member functions.
void action()
{
std::cout << "action()" << std::endl;
}
int times_two(int x)
{
std::cout << "times_two()" << std::endl;
return 2 * x;
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose class and member-function.
python::class_<spam>("Spam")
.def("action", &spam::action)
.def("times_two", boost::function<int(spam&, int)>(
&spam::times_two))
;
// Expose non-member function.
python::def("action", &action);
python::def("times_two", boost::function<int()>(
boost::bind(×_two, 21)));
}
And its usage:
>>> import example
>>> spam = example.Spam()
>>> spam.action()
spam::action()
>>> spam.times_two(5)
spam::times_two()
10
>>> example.action()
action()
>>> example.times_two()
times_two()
42
When providing a functor that will invoke a member-function, the provided signature needs to be the non-member function equivalent. In this case, int(spam::*)(int) becomes int(spam&, int).
// ...
.def("times_two", boost::function<int(spam&, int)>(
&spam::times_two))
;
Also, arguments can be bound to the functors with boost::bind. For example, calling example.times_two() does not have to provide an argument, as 21 is already bound to the functor.
python::def("times_two", boost::function<int()>(
boost::bind(×_two, 21)));
Custom functor with guards
Expanding upon the above example, one can enable custom functor types to be used with Boost.Python. Lets create a functor, called guarded_function, that will use RAII, only invoking the wrapped function during the RAII object's lifetime.
/// #brief Functor that will invoke a function while holding a guard.
/// Upon returning from the function, the guard is released.
template <typename Signature,
typename Guard>
class guarded_function
{
public:
typedef typename boost::function_types::result_type<Signature>::type
result_type;
template <typename Fn>
guarded_function(Fn fn)
: fn_(fn)
{}
result_type operator()()
{
Guard g;
return fn_();
}
// ... overloads for operator()
private:
boost::function<Signature> fn_;
};
The guarded_function provides similar semantics to the Python with statement. Thus, to keep with the Boost.Python API name choices, a with() C++ function will provide a way to create functors.
/// #brief Create a callable object with guards.
template <typename Guard,
typename Fn>
boost::python::object
with(Fn fn)
{
return boost::python::make_function(
guarded_function<Guard, Fn>(fn), ...);
}
This allows for functions to be exposed which will run with a guard in a non-intrusive manner:
class no_gil; // Guard
// ...
.def("times_two", with<no_gil>(&spam::times_two))
;
Additionally, the with() function provides the ability to deduce the function signatures, allowing the meta-data signature to be explicitly provided to Boost.Python rather than having to overload boost::python::detail::get_signature().
Here is the complete example, using two RAII types:
no_gil: Releases GIL in constructor, and reacquires GIL in destructor.
echo_guard: Prints in constructor and destructor.
#include <iostream>
#include <boost/function.hpp>
#include <boost/function_types/components.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/python.hpp>
#include <boost/tuple/tuple.hpp>
namespace detail {
/// #brief Functor that will invoke a function while holding a guard.
/// Upon returning from the function, the guard is released.
template <typename Signature,
typename Guard>
class guarded_function
{
public:
typedef typename boost::function_types::result_type<Signature>::type
result_type;
template <typename Fn>
guarded_function(Fn fn)
: fn_(fn)
{}
result_type operator()()
{
Guard g;
return fn_();
}
template <typename A1>
result_type operator()(A1 a1)
{
Guard g;
return fn_(a1);
}
template <typename A1, typename A2>
result_type operator()(A1 a1, A2 a2)
{
Guard g;
return fn_(a1, a2);
}
private:
boost::function<Signature> fn_;
};
/// #brief Provides signature type.
template <typename Signature>
struct mpl_signature
{
typedef typename boost::function_types::components<Signature>::type type;
};
// Support boost::function.
template <typename Signature>
struct mpl_signature<boost::function<Signature> >:
public mpl_signature<Signature>
{};
/// #brief Create a callable object with guards.
template <typename Guard,
typename Fn,
typename Policy>
boost::python::object with_aux(Fn fn, const Policy& policy)
{
// Obtain the components of the Fn. This will decompose non-member
// and member functions into an mpl sequence.
// R (*)(A1) => R, A1
// R (C::*)(A1) => R, C*, A1
typedef typename mpl_signature<Fn>::type mpl_signature_type;
// Synthesize the components into a function type. This process
// causes member functions to require the instance argument.
// This is necessary because member functions will be explicitly
// provided the 'self' argument.
// R, A1 => R (*)(A1)
// R, C*, A1 => R (*)(C*, A1)
typedef typename boost::function_types::function_type<
mpl_signature_type>::type signature_type;
// Create a callable boost::python::object that delegates to the
// guarded_function.
return boost::python::make_function(
guarded_function<signature_type, Guard>(fn),
policy, mpl_signature_type());
}
} // namespace detail
/// #brief Create a callable object with guards.
template <typename Guard,
typename Fn,
typename Policy>
boost::python::object with(const Fn& fn, const Policy& policy)
{
return detail::with_aux<Guard>(fn, policy);
}
/// #brief Create a callable object with guards.
template <typename Guard,
typename Fn>
boost::python::object with(const Fn& fn)
{
return with<Guard>(fn, boost::python::default_call_policies());
}
/// #brief Mockup class with member functions.
class spam
{
public:
void action()
{
std::cout << "spam::action()" << std::endl;
}
int times_two(int x)
{
std::cout << "spam::times_two()" << std::endl;
return 2 * x;
}
};
// Mockup non-member functions.
void action()
{
std::cout << "action()" << std::endl;
}
int times_two(int x)
{
std::cout << "times_two()" << std::endl;
return 2 * x;
}
/// #brief Guard that will unlock the GIL upon construction, and
/// reacquire it upon destruction.
struct no_gil
{
public:
no_gil() { state_ = PyEval_SaveThread();
std::cout << "no_gil()" << std::endl; }
~no_gil() { std::cout << "~no_gil()" << std::endl;
PyEval_RestoreThread(state_); }
private:
PyThreadState* state_;
};
/// #brief Guard that prints to std::cout.
struct echo_guard
{
echo_guard() { std::cout << "echo_guard()" << std::endl; }
~echo_guard() { std::cout << "~echo_guard()" << std::endl; }
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose class and member-function.
python::class_<spam>("Spam")
.def("action", &spam::action)
.def("times_two", with<no_gil>(&spam::times_two))
;
// Expose non-member function.
python::def("action", &action);
python::def("times_two", with<boost::tuple<no_gil, echo_guard> >(
×_two));
}
And its usage:
>>> import example
>>> spam = example.Spam()
>>> spam.action()
spam::action()
>>> spam.times_two(5)
no_gil()
spam::times_two()
~no_gil()
10
>>> example.action()
action()
>>> example.times_two(21)
no_gil()
echo_guard()
times_two()
~echo_guard()
~no_gil()
42
Notice how multiple guards can be provided by using a container type, such as boost::tuple:
python::def("times_two", with<boost::tuple<no_gil, echo_guard> >(
×_two));
When invoked in Python, example.times_two(21) produces the following output:
no_gil()
echo_guard()
times_two()
~echo_guard()
~no_gil()
42
If someone is interested, I had a small issue with Tanner Sansbury's code when using his final working example. For some reason, I still had the problem he mentioned about having the wrong signature in the final generated boost::function:
// example for spam::times_two:
// correct signature (manual)
int (spam::*, int)
// wrong signature (generated in the `guarded_function` wrapper)
int (spam&, int)
even when overloading boost::python::detail::get_signature(). The responsible for this was boost::function_types::components; it has a default template parameter ClassTranform = add_reference<_> which creates this class reference. To fix this, I simply changed the mpl_signature struct as follow:
// other includes
# include <boost/type_traits/add_pointer.hpp>
# include <boost/mpl/placeholders.hpp>
template <typename Signature> struct mpl_signature
{
typedef typename boost::function_types::components<Signature,
boost::add_pointer<boost::mpl::placeholders::_> >::type type;
};
template <typename Signature> struct mpl_signature<boost::function<Signature> >
{
typedef typename boost::function_types::components<Signature>::type type;
};
And now everything works like a charm.
If someone can confirm this is indeed the right fix, I'd be interested :)
Related
Let's say I declare a thread with the following code:
#include <thread>
#include <iostream>
void printStuff(const char* c, long x) {
std::cout << x << " bottles of " << c << " on the wall\n";
}
int main()
{
std::thread t(printStuff, "beer", 900000000);
t.join();
}
How are the arguments printStuff, "beer," and 900000000 stored in the thread?
I know they are using a variadic template, where you first pass in a function and then a parameter pack of arguments. I am confused on how they forward all these template arguments, and then somehow call the inputted function with all the arguments when join or detach is called.
std::function has similar functionality where when you call std::bind it will store a function and its arguments inside the object, and then when you call the std::function object it will just execute the bound function with its arguments.
I am basically trying to implement my own version of std::function, for my own edification. I am curious how in C++ you would go about storing a function with a bunch of arbitrary parameters inside an object, and then having a method that would call the function with the passed in arguments.
I have looked at both the thread and std::function class, and both seem to be using tuples in some way to store their arguments. In a declaration of a tuple you have to specify what types you are storing in it:
std::tuple<int, std::string> tup;
How do std::function and thread get around this by storing their variadic arguments in tuples? Furthermore, how do they retrieve the function and call it with all of the arguments?
I am basically trying to implement my own version of std::function, for my own edification. I am curious how in C++ you would go about storing a function with a bunch of arbitrary parameters inside an object, and then having a method that would call the function with the passed in arguments.
std::function is a beast of a class so I won't pretend that this is anywhere close to as complete. std::function uses type erasure and small object optimization but I'll use polymorphism and store a base class pointer to a semi-anonymous implementation of a function wrapper to show how it can be done. I say semi-anonymous because it actually has a name, but it's defined locally inside the function that instantiates it. Storing the pointer (or the empty state) will be done in a std::unique_ptr<funcbase>.
The goal, as I've understood it, is to create a class with this basic interface:
template <class R, class... Args>
class fn_with_args<R(Args...)> {
public:
template <class F> fn_with_args(F&& f, Args&&... args);
R operator()();
};
That is, we need instances of fn_with_args<R(Args...)> to be able to store function pointers / functors that when invoked with the stored arguments returns R.
#include <functional>
#include <memory>
#include <tuple>
template <class> class fn_with_args; // not implemented
template <class R, class... Args>
class fn_with_args<R(Args...)> {
// an abstract base for cloneable function objects with an operator()() to call
struct funcbase {
virtual ~funcbase() = default;
virtual std::unique_ptr<funcbase> clone() const = 0;
virtual R operator()() = 0;
};
public:
// create empty "fn_with_args":
fn_with_args() noexcept = default;
fn_with_args(std::nullptr_t) noexcept {};
// copy ctor - if store contains a pointer to a funcbase,
// let it clone itself
fn_with_args(const fn_with_args& other) :
store(other.store ? other.store->clone() : nullptr) {}
// copy assignment
fn_with_args& operator=(const fn_with_args& other) {
if(this != &other) *this = fn_with_args(other); // copy+move
return *this;
}
// moving can be done by default:
fn_with_args(fn_with_args&& other) noexcept = default;
fn_with_args& operator=(fn_with_args&& other) noexcept = default;
// constructing and storing arguments
template <class F>
fn_with_args(F&& f, Args&&... args) {
// the semi-anonymous implementation that inherits from funcbase
// and stores both the function and the arguments:
struct funcimpl : funcbase {
funcimpl(F&& f, Args&&... a)
: func{std::forward<F>(f)}, args{std::forward<Args>(a)...} {}
// cloning via a base class pointer:
std::unique_ptr<funcbase> clone() const override {
return std::make_unique<funcimpl>(*this);
}
// the operator that will call `func` with the stored arguments:
R operator()() override { return std::apply(func, args); }
F func; // the actual function/functor
std::tuple<Args...> args; // and the stored arguments
};
// create and store an instance of the above semi-anonymous class:
store = std::make_unique<funcimpl>(std::forward<F>(f),
std::forward<Args>(args)...);
}
// The call interface. It'll dereference `store` and then call it which
// will call the overridden operator()() in the semi-anonymous `funcimpl`:
R operator()() {
if(store) return (*store)();
throw std::bad_function_call();
}
private:
std::unique_ptr<funcbase> store;
};
Example usage:
#include <iostream>
double foo(int x) {
return x * 3.14159;
}
int main() {
fn_with_args<int(double)> f1([](double d) -> int { return d; }, 3.14159);
std::cout << f1() << '\n';
fn_with_args<void()> f2; // create empty
//f2(); // would throw "bad_function_call" since it is "empty"
// populate it
f2 = fn_with_args<void()>([]{ std::cout << "void\n"; });
f2();
// call regular function:
fn_with_args<double(int)> f3(foo, 2);
std::cout << f3() << '\n';
// example with capture:
int v = 123;
f1 = fn_with_args<int(double)>([v](double d) -> int { return v * d; }, 3.14159);
std::cout << f1() << '\n';
// copying:
auto f11 = f1;
std::cout << f11() << '\n'; // calling the copy
}
Demo
you should store the params in std::tuple and invoke them using std::apply
#include <functional>
#include <tuple>
#include <vector>
template <class R>
class Function_Wrapper {
public:
template <typename Callable, typename... Args>
Function_Wrapper(Callable&& callable, Args&&... args)
: fn_([=, args = std::make_tuple(std::forward<Args>(args)...)]() {
return std::apply(callable, args);
}) {}
decltype(auto) run() {
// call our callable with the passed in arguments
return fn_();
}
decltype(auto) operator()() { return run(); }
private:
std::function<R()> fn_;
};
int add(int a, int b) { return a + b; }
int main() {
std::vector<Function_Wrapper<int>> f{{&add, 9, 30}, {&add, 1, 2}};
return f[0].run() + f[1]();
}
Here in Compiler Explorer
I want to pass pointers of some functions to a template class to use them later. I was wondering if:
Does it make a possibly (speed-wise) beneficial difference if I make these functions inline?
Functions themselves are possibly one line wrapper for another functions like the example below:
//inline ?
void func_wrapper_1(){
func1(arg1);
}
//inline ?
void func_wrapper_2(){
func2(arg2);
}
and the class template is like the example below:
template<void(*f1)(), void(*f2)()>
class caller{
public:
static void func(int v){
if(v) {
(*f1)();
}else{
(*f2)();
}
}
};
And later on in the main function it will be used like the example below:
caller<func_wrapper_1,func_wrapper_2>::func(0);
caller<func_wrapper_1,func_wrapper_2>::func(1);
I know that every things depends on compiler and compiling option, but lets assume compiler accepts to make these functions inline.
Whether or not a compiler will be smart enough to inline a given situation is up for grabs but I think it may be possible by creating Callable Types by overloading the function call operator.
Something like this:
template<typename Func1, typename Func2>
class caller{
public:
static void func(int v){
if(v) {
// Func1() - creates an object of type Func1
// that object is 'called' using the '()' operator
Func1()();
}else{
Func2()();
}
}
};
struct CallableType1
{
// overloading the function call operator makes objects of
// this type callable
void operator()() const { std::cout << "callable 1" << '\n'; }
};
struct CallableType2
{
void operator()() const { std::cout << "callable 2" << '\n'; }
};
int main()
{
caller<CallableType1, CallableType2> cc;
cc.func(2);
}
I had a templated class that had a getter function and a setter function pointer. When I created an object of this class and I didn't want its setter to do anything I'd just pass nullptr as the setter function argument. Then at runtime, it would check if its setter pointer was nullptr to see whether it should call the setter.
Using a function pointer isn't good enough now because I want the class to be able to store a lambda. So instead of a function pointer the setter is now a template type argument. Before I used to pass a nullptr to signify that there was no setter, but now I can't, so I use a dummy char member, as you can see:
template <typename GetFunctionType, typename SetFunctionType = char>
class MyClass
{
public:
MyClass(GetFunctionType getFunction, SetFunctionType setFunction = char(0))
: getFunction(getFunction), setFunction(setFunction)
{}
GetFunctionType getFunction;
SetFunctionType setFunction;
typedef decltype(getFunction()) ReturnType;
void set(ReturnType value)
{
if constexpr (std::is_invocable_v<decltype(setFunction), ReturnType>)
{
setFunction(value);
std::cout << "Setter called\n";
}
else
{
// ELSE DO NOTHING
std::cout << "Object has no setter\n";
}
}
};
int main()
{
MyClass foo([]() { return 7; }, [](int val) { std::cout << "You have set the value\n"; });
MyClass foo2([]() {return 7; }); // THIS OBJECT HAS NO SETTER, BUT HAS A CHAR
// MEMBER THAT I USED AS A DUMMY
foo.set(1);
foo2.set(1);
}
My question is do I need that dummy char in cases where the object has no setter function?
Using a function pointer isn't good enough now because I want the
class to be able to store a lambda!
Not completely true!
You could store the capture-less lambdas to the typed-function pointers.
See [expr.prim.lambda.closure] (sec 7)
The closure type for a non-generic lambda-expression with no
lambda-capture whose constraints (if any) are satisfied has a
conversion function to pointer to function with C++ language linkage
having the same parameter and return types as the closure type's
function call operator.
In addition to that, normally a getter would have a signature
ReturnType /*const-ref*/ <function>();
similarly, the setter would have
void <function>(ArgumentType) /*const*/; // where ReturnType == ArgumentType usually
Combining these two information, I am suggesting the following re-structuring of your class.
(See live demo online)
#include <iostream>
#include <string>
template <typename ArgType>
class MyClass final
{
// alias types
using GetFunctionType = ArgType(*)(void);
using SetFunctionType = void(*)(ArgType);
GetFunctionType getFunction;
SetFunctionType setFunction;
public:
// Now you can set the function pointer to by default `nullptr`
MyClass(GetFunctionType getFunction = nullptr, SetFunctionType setFunction = nullptr)
: getFunction{getFunction}
, setFunction{setFunction}
{}
void set(ArgType value) const noexcept
{
if (getFunction && setFunction) // runtime nullptr check
{
setFunction(value);
std::cout << "Setter called\n\n\n";
} else {
std::cout << "Object has no setter\n\n";
}
}
};
int main()
{
// mention the argument type
MyClass<int> foo(
[]() { return 7; },
[](int val) { std::cout << "You have set the value: " << val << "\n"; }
);
MyClass<std::string> foo2([]() {return std::string{}; }); // also works
foo.set(1);
foo2.set("String");
}
It would be good if there was a way you could pass void or 'something'
so that when you declare a class member like this: T setFunction; the
compiler just removes it from the class.
To my understanding, when you do the partial specialization, you do not even need to declare the setFunctionat all.
Following is the example code, in which the first specialization
template <typename Getter, typename Setter>
class MyClass final{};
handles the when you provide Getter and Setter cases, whereas the second one handles the no setter situation.
template <typename Getter>
class MyClass<Getter, std::nullptr_t> final
Unfortunately, you still need to specify the second argument (i.e. std::nullptr_t{}) in order to choose the correct specialization.
(See live demo online)
#include <iostream>
#include <cstddef> // std::nullptr_t
template <typename Getter, typename Setter>
class MyClass final
{
Getter mGetFunction;
Setter mSetFunction;
using ReType = decltype(mGetFunction());
static_assert(std::is_invocable_v<decltype(mGetFunction)>, " Getter is not callable!");
static_assert(std::is_invocable_v<decltype(mSetFunction), ReType>, " Setter is not callable!");
public:
MyClass(Getter mGetFunction, Setter mSetFunction) noexcept
: mGetFunction{ mGetFunction }
, mSetFunction{ mSetFunction }
{}
void set(ReType value) const noexcept {
mSetFunction(value);
std::cout << "Setter called\n";
}
};
template <typename Getter>
class MyClass<Getter, std::nullptr_t> final
{
Getter mGetFunction;
using ReType = decltype(mGetFunction());
static_assert(std::is_invocable_v<decltype(mGetFunction)>, " Getter is not callable!");
public:
MyClass(Getter mGetFunction, std::nullptr_t) noexcept
: mGetFunction{ mGetFunction }
{}
void set(ReType value) const noexcept {
std::cout << "Object has no setter\n";
}
};
int main()
{
MyClass foo{
[]() { return 7; },
[](int val) { std::cout << "You have set the value\n"; }
};
foo.set(1);
//unfortunately, needed to pass second argument for class instantiation
MyClass foo2([]() {return 7; }, std::nullptr_t{});
foo2.set(1);
}
I would like to represent the following code using a UML diagram:
#include <iostream>
#include <boost/bind.hpp>
using namespace std;
class A {
public:
void bar() {std::cout << "A::bar()" << std::endl;}
};
// FUNC should be callable with arguments (int, A*)
template <typename FUNC>
class B {
public:
B(FUNC func, int data) : func_(func), data_(data){}
void operator()(A* ap){func_(data_, ap);}
FUNC func_;
int data_;
};
// object generator uses argument deduction to construct B
template <typename FUNC>
B<FUNC> makeB(FUNC func, int data) {
return B<FUNC>(func, data);
}
struct F {
static void apply(int a, int b, A* ap){
std::cout << "a+b = " << a + b << std::endl;
ap->bar();
}
};
int main() {
A* a = new A;
auto b = makeB(boost::bind(F::apply, 10, _1, _2), 20);
b(a);
}
Here is my first attempt. I think there is some room for improvement:
Should I capture pointers to F and A in the bind attributes or represent them serparately? Currently I'm showing both. I think the syntax for the F::apply attribute is also wrong.
What is the best way to write the signature template for the bind class?
Is there a better way to use decltype in B's template parameter? currently it looks a bit clumsy.
The purpose is to communicate how bind works to people who may not be familiar with it and perhaps convey a little about how bind works internally. The diagram should be as simple as possible so any hacks that are intuitive and not misleading are okay, it doesn't have to conform precisely to the UML standard.
update: This version fixes the type of bind's internal function pointer.
For a library, I'd like a function to accept another function and its arguments, then store them all for calling later. The arguments must allow for any mixture of types, but the functions only need to return void. Something like this:
void myFunc1(int arg1, float arg2);
void myFunc2(const char *arg1);
class DelayedCaller
{ ...
public:
static DelayedCaller *setup(Function func, …);
};
...
DelayedCaller* caller1 = DelayedCaller::setup(&myFunc1, 123, 45.6);
DelayedCaller* caller2 = DelayedCaller::setup(&myFunc2, "A string");
caller1->call(); // Calls myFunc1(), with arguments 123 and 45.6
caller2->call(); // Calls myFunc2(), with argument "A string"
One approach is to make DelayedCaller::setup() accept a std::function, and have my library users use std::bind() prior to calling setup(). However, is there a way to implement setup() such that users don't need to do the binding themselves?
Edit: DelayedCaller is an existing class. setup() is a new static method I'd like to add.
An possibility is to use variadic templates and call std::bind() from within the setup() function:
#include <iostream>
#include <string>
#include <functional>
#include <memory>
void myFunc1(int arg1, float arg2)
{
std::cout << arg1 << ", " << arg2 << '\n';
}
void myFunc2(const char *arg1)
{
std::cout << arg1 << '\n';
}
class DelayedCaller
{
public:
template <typename TFunction, typename... TArgs>
static std::unique_ptr<DelayedCaller> setup(TFunction&& a_func,
TArgs&&... a_args)
{
return std::unique_ptr<DelayedCaller>(new DelayedCaller(
std::bind(std::forward<TFunction>(a_func),
std::forward<TArgs>(a_args)...)));
}
void call() const { func_(); }
private:
using func_type = std::function<void()>;
DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
func_type func_;
};
int main()
{
auto caller1(DelayedCaller::setup(&myFunc1, 123, 45.6));
auto caller2(DelayedCaller::setup(&myFunc2, "A string"));
caller1->call();
caller2->call();
return 0;
}
Output:
123, 45.6
A string
Return a smart pointer, such as std::unique_ptr, instead of returning a raw pointer (or return by value and avoid dynamic allocation. The func_type is moveable if the arguments are moveable, or it may be quite cheap to copy anyway. You may need to define the move constructor and move assignment operator, they are generated under certain conditions).
You could use lambda functions to hide the bindings:
#include <functional>
class DelayedCaller : public std::function< void(void) > {
public:
DelayedCaller(std::function< void(void) > fn)
: std::function< void(void) >(fn) {}
};
DelayedCaller caller1([]() { myFunc1(123, 45.6); });
DelayedCaller caller2([]() { myFunc2("A string"); });
caller1(); // Calls myFunc1(), with arguments 123 and 45.6
caller2(); // Calls myFunc2(), with argument "A string"
This also gives your library's users more flexibility. They're not limited to a single function call and the functions have access to the original environment they were created in:
int x;
DelayedCaller caller3 = [&x]() {
if (x == 0)
DoSomething();
else
DoSomethingElse();
};
If your only concern is to hide the argument binding from the callsite while keeping your interface, use variadic templates
class DelayedCaller
{
public:
template<typename... Args>
static DelayedCaller* setup(void (functionPtr*)(Args...), Args&&... args)
{
return new DelayedCaller(std::bind(functionPtr, std::forward<Args>(args)...));
}
DelayedCaller(const std::function<void()>& f) : f(f) {}
private:
std::function<void()> f;
};
The public constructor still offers your users the possibility to initialize it with a lambda is they wish.
If you want/are able to make use of the C++11 future library you can use std::async
#include <future>
auto caller = std::async(myFunc1, 123, 45.6); // Creates a future object.
caller.get(); // Waits for the function to get executed and returns result.
To force lazy evaluation use:
auto caller = std::async(std::launch::deferred, myFunc1, 123, 45.6);
Also this has the advantage that the function call might be executed on a different thread which makes use of multicore hardware. However this may not be suitable in every case.