after yesterday's rip-roaring thread at How to implement a simple event queue? , I decided to finally make the big leap to c++11. Just before c++14 comes out probably...
Anyway, it occured to me that variadic functions are the perfect way forward in this enjoyable endeavour. They probably aren't really, but anyway, I managed to steal and bastardize some code I found somewhere, and ended up with this:
#include <iostream>
#include <functional>
#include <queue>
class Event
{
public:
int timeOfCompletion;
std::function<void()> function;
inline bool operator<(const Event& target) const
{
return target.timeOfCompletion < timeOfCompletion;
}
};
class System
{
public:
int someValue;
std::priority_queue<Event> funcs;
System()
{
someValue = 100;
}
template<typename Func, typename...Args>
void addFunctionToQueue(const int t , const Func&& myFunc, Args&&... myArgs)
{
Event newEvent;
std::function<void()> func = std::bind( std::forward<Func>(myFunc), std::ref(myArgs)...);
newEvent.function = func;
newEvent.timeOfCompletion = t;
funcs.push(newEvent);
}
void runAllFunctions()
{
while(!funcs.empty())
{
Event func = funcs.top();
funcs.pop();
func.function();
}
}
static void doStaticFunction(int a)
{
std::cout <<"I would like to change someValue here, but can't :-(\n";
//someValue -= a;//invalid
}
void doNonStaticFunction(int a)
{
someValue -= a;
std::cout <<"Set someValue to " << someValue << "\n";
}
};
int main()
{
System newSystem;
newSystem.doNonStaticFunction(5);
newSystem.addFunctionToQueue(5, System::doStaticFunction, 1);
newSystem.runAllFunctions();
//newSystem.addFunctionToQueue(5, newSystem.doStaticFunction, 1);// is invalid
//newSystem.addFunctionToQueue(5, System::doNonStaticFunction, 1);// is invalid
//newSystem.addFunctionToQueue(5, newSystem.doNonStaticFunction, 1);// is invalid
std::cin.ignore();
return 0;
}
Anyhow, how can I get the "addFunctionToQueue" function to work with non-static functions? I thought I had more questions, but I think if I can get that one answered, my other problems will hopefully be solved...
Remove a const qualifier from the Func parameter.
template<typename Func, typename...Args>
void addFunctionToQueue(int t , Func&& myFunc, Args&&... myArgs)
// ~~~^ no const
Rationale: When using a forwarding reference (or an lvalue reference) type with a template argument deduction, a const qualifier is automatically deduced (depending on the argument's qualifiers). Giving it explicitly prevents the compiler from adding it to the Func type itself, which results in an error when you try to std::forward<Func>. That said, you would need to write std::forward<const Func> instead to avoid the compiler error, but still, that would make no sense, as const T&& is not a forwarding reference.
Non-static member functions require an object for which they will be called, just like you write a.foo(), not foo().
newSystem.addFunctionToQueue(5, &System::doNonStaticFunction, &newSystem, 1);
// ~~~~~~~~~^ context
Related
I have a fairly big project that, regarding this question,
I can summarize with
this structure:
void do_something()
{
//...
}
template<typename F> void use_funct(F funct)
{
// ...
funct();
}
int main()
{
// ...
use_funct(do_something);
}
All is working ok until someone (me) decides to reformat a little
minimizing some functions, rewriting
as this minimum reproducible example:
void do_something(const int a, const int b)
{
//...
}
void do_something()
{
//...
do_something(1,2);
}
template<typename F> void use_funct(F funct)
{
// ...
funct();
}
int main()
{
// ...
use_funct(do_something);
}
And now the code doesn't compile with
error: no matching function for call
where use_funct is instantiated.
Since the error message was not so clear to me
and the changes were a lot I wasted a considerable
amount of time to understand that the compiler
couldn't deduce the template parameter
because do_something could now refer to
any of the overloaded functions.
I removed the ambiguity changing the function name,
but I wonder if there's the possibility to avoid
this error in the future not relying on template
argument deduction.
How could I specify in this case the template argument for do_something(), possibly without referring to a function pointer?
I haven't the slightest idea to express explicitly:
use_funct<-the-one-with-no-arguments->(do_something);
You can wrap the function in a lambda, or pass a function pointer after casting it to the type of the overload you want to call or explicitly specify the template parameter:
use_funct([](){ do_something (); });
use_funct(static_cast<void(*)()>(do_something));
use_funct<void()>(do_something);
Wrapping it in a lambda has the advantage, that it is possible to defer overload resolution to use_func. For example:
void do_something(int) {}
void do_something(double) {}
template<typename F> void use_funct(F funct) {
funct(1); // calls do_something(int)
funct(1.0); // calls do_something(double)
}
int main() {
use_funct([](auto x){ do_something (x); });
}
[...] possibly without referring to a function pointer?
I am not sure what you mean or why you want to avoid that. void() is the type of the function, not a function pointer. If you care about spelling out the type, you can use an alias:
using func_type = void();
use_funct<func_type>(do_something);
I have a class that is trying to encapsulate the setup of an interrupt. I need to pass an instantiated reference/pointer/etc to an external function that then calls my function.
I can't change this function:
typedef void (*voidFuncPtr)(void);
void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode);
My Library:
class Buttons ...
bool Buttons::begin(int buttonPin)
{
//attachInterrupt(buttonPin, (this->*func)Buttons::released, HIGH);
attachInterrupt(buttonPin, &Buttons::released, LOW);
return 0;
}
void Buttons::released()
{
numButtonPresses++;
pressLength = millis()-pressStartTime;
pressStartTime = 0;
buttonState=LOW;
}
The problem is that I don't know what to put inside the attachInterupt function in the Buttons::begin method. I am sure I am doing something wrong in the way I am approaching this problem, but I am not sure what it is or what I should do about it. I would greatly appreciate any suggestions!
You're using an old c-style function pointer callback. This does not work for member function of an object. If you can't change the callback, you need to make the Buttons::released function static.
The problem you were facing is that you wanted to pass two pieces of data as your callback: the member function, and a class instance to call that member function on.
With the existing interface, which only accepts a function pointer with no arguments, you might create a static Button object and then write a static wrapper function that calls someStaticButton.released(). Then you could pass the address of this wrapper function as your callback. Justin Time’s answer approaches from a different, and clever, direction: wrap the instance and member in a singleton class, and give that a static member callback function. A simpler way to allow more than one singleton class would be to add a numeric ID as template parameter.
You might also be able to make button::released() a static member function, but your implementation appears to refer to member data. This wouldn’t be an option unless there is only one button in the program, represented by a singleton class.
If you can pass the instance pointer as the first argument to your callback function, or any other argument that can do a round-trip conversion to and from an object pointer (such as void* or any integer as wide as intptr_t), you can make the member function static and pass the this pointer as its argument.
If you can overload attachInterrupt to take a std::function object as your callback, you can do what you originally wanted. This type can represent a static function, a member function, or a closure containing a member function and a this pointer.
You unfortunately say you cannot change the callback function, but perhaps you can extend the interface in a backward-compatible way, such as:
#include <array>
#include <iostream>
#include <functional>
#include <stdint.h>
#include <stdlib.h>
#include <utility>
using std::cout;
using std::endl;
using voidFuncPtr = void(*)(void);
using Callback = std::function<void(void)>;
std::array<Callback, 1> interrupts;
void attachInterruptEx( const uint32_t pin,
Callback&& callback,
const uint32_t /* unused */ )
{
interrupts.at(pin) = std::move(callback);
}
void attachInterrupt( const uint32_t pin,
const voidFuncPtr callbackPtr,
const uint32_t mode )
{
/* Passing callbackPtr to a function that expects Callback&& implicitly
* invokes the constructor Callback(voidFuncPtr). This is sugar for
* std::function<void(void)>(void(*)(void)). That is, it initializes a
* temporary Callback object from callbackPtr.
*/
return attachInterruptEx( pin, callbackPtr, mode );
}
class Buttons {
public:
Buttons() = default;
bool begin(int buttonPin);
void released();
unsigned long buttonPresses() { return numButtonPresses; }
private:
// Empty stub function, probably calls a timer.
unsigned long millis() { return 0; };
static constexpr uint32_t LOW = 0;
uint32_t buttonState = LOW;
unsigned long numButtonPresses = 0;
unsigned long pressStartTime = 0;
unsigned long pressLength = 0;
};
/* Per C++17, a constant known at compile time is not odr-used, so this
* definition is deprecated. Still included out of an abundance of caution.
* It cannot have an initializer.
*/
constexpr uint32_t Buttons::LOW;
bool Buttons::begin(int buttonPin)
{
/* The C++17 Standard says little about the return type of std::bind().
* Since the result is a callable object, a std::function can be initialized
* from it. I make the constructor call explicit in case the return type of
* std::bind is a subclass of std::function in some implementation, and
* it resolves the overload in a way we don't expect.
*/
attachInterruptEx( static_cast<uint32_t>(buttonPin),
Callback(std::bind(&Buttons::released, this)),
LOW );
return false;
}
void Buttons::released()
{
numButtonPresses++;
pressLength = millis()-pressStartTime;
pressStartTime = 0;
buttonState=LOW;
}
int main(void)
{
Buttons buttons;
buttons.begin(0);
interrupts[0]();
// Should be 1.
cout << buttons.buttonPresses() << endl;
return EXIT_SUCCESS;
}
[Note that this code will use the following simplified version of your MCVE, primarily to have an easily-usable callback caller when testing & demonstrating the implementation:]
// Pointer type.
typedef void (*voidFuncPtr)(void);
// Dummy callback callers.
void takesVoidFuncPtr(voidFuncPtr vfp) {
std::cout << "Now calling vfp...\n";
vfp();
std::cout << "vfp called.\n";
}
struct DelayedCaller {
voidFuncPtr ptr;
DelayedCaller(voidFuncPtr p) : ptr(p) {}
void callIt() { return ptr(); }
};
// Simple stand-in for Button.
struct HasMemberFunction {
std::string name;
HasMemberFunction(std::string n) : name(std::move(n)) {}
void memfunc() { std::cout << "-->Inside " << name << ".memfunc()<--\n"; }
void funcmem() { static std::string out("Don't call me, I'm lazy. >.<\n"); std::cout << out; }
};
// Calling instance.
HasMemberFunction hmf("instance");
Ideally, you'd be able to bind the function to an instance with a lambda, and pass that to the consuming function as the callback. Unfortunately, though, capturing lambdas can't be converted to non-member function pointers, so this option isn't viable. However...
[Note that I have omitted proper encapsulation both for brevity, and for a demonstration of this approach's caveats at the end of the answer. I would recommend adding it if you actually use this.]
// Helper.
// Can easily be simplified if desired, Caller and MultiCaller only use FuncPtrTraits::ContainingClass.
namespace detail {
template<typename...> struct Pack {};
template<typename T> struct FuncPtrTraits;
template<typename Ret, typename Class, typename... Params>
struct FuncPtrTraits<Ret (Class::*)(Params...)> {
using ReturnType = Ret;
using ContainingClass = Class;
using ParameterList = Pack<Params...>;
};
template<typename T>
using ContainingClass = typename FuncPtrTraits<T>::ContainingClass;
} // detail
// Calling wrapper.
// Only allows one pointer-to-member-function to be wrapped per class.
template<typename MemFunc, typename Class = detail::ContainingClass<MemFunc>>
struct Caller {
static_assert(std::is_member_function_pointer<MemFunc>::value, "Must be built with pointer-to-member-function.");
static Class* c;
static MemFunc mf;
static void prep(Class& cls, MemFunc mem) { c = &cls; mf = mem; }
static void clean() { c = nullptr; mf = nullptr; }
static void call() { return (c->*mf)(); }
// Constructor is provided for convenience of creation, to effectively tie prep() to deduction guide.
// Note that it operates on static members only.
// Convenient, but likely confusing. ...Probably best not to do this. ;3
Caller(Class& cls, MemFunc mem) { prep(cls, mem); }
// Default constructor is required if we provide the above hax ctor.
Caller() = default;
};
template<typename MemFunc, typename Class> Class* Caller<MemFunc, Class>::c = nullptr;
template<typename MemFunc, typename Class> MemFunc Caller<MemFunc, Class>::mf = nullptr;
We can instead provide the desired behaviour by using a wrapper class, which stores the desired function and instance as static member variables, and provides a static member function that matches voidFuncPtr and contains the actual, desired function call. It can be used like so:
std::cout << "\nSimple caller, by type alias:\n";
using MyCaller = Caller<decltype(&HasMemberFunction::memfunc)>;
MyCaller::prep(hmf, &HasMemberFunction::memfunc);
takesVoidFuncPtr(&MyCaller::call);
MyCaller::clean(); // Not strictly necessary, but may be useful once the callback will no longer be called.
// Or...
std::cout << "\nSimple caller, via dummy instance:\n";
Caller<decltype(&HasMemberFunction::memfunc)> caller;
caller.prep(hmf, &HasMemberFunction::memfunc);
takesVoidFuncPtr(&caller.call);
caller.clean(); // Not strictly necessary, but may be useful once the callback will no longer be called.
That's a bit of a mess, so a hacky constructor is provided to simplify it.
[Note that this may violate the principle of least astonishment, and thus isn't necessarily the best option.]
std::cout << "\nSimple caller, via hax ctor:\n";
Caller clr(hmf, &HasMemberFunction::memfunc);
takesVoidFuncPtr(&clr.call);
clr.clean(); // Not strictly necessary, but may be useful once the callback will no longer be called.
Now, this version only allows one function to be wrapped per class. If multiple functions per class are required, we'll need to expand it a little.
[Note that this would be pretty awkward to typedef, as the optimal template parameter order places the first pointer-to-member-function first, to allow Class to be automatically deduced if only one function needs to be wrapped; the "hax ctor" approach was primarily intended for this version of Caller, although a deduction guide could likely also be used to swap Class and MemFunc.]
[Also note that all wrapped member functions must have the same signature.]
// Calling wrapper.
// Slightly more complex version, allows multiple instances of MemFunc to be wrapped.
template<typename MemFunc, typename Class = detail::ContainingClass<MemFunc>, typename... MemFuncs>
struct MultiCaller {
static_assert(std::is_member_function_pointer<MemFunc>::value, "Must be built with pointer-to-member-function.");
static_assert(std::conjunction_v<std::is_same<MemFunc, MemFuncs>...>, "All pointers-to-member-function must be the same type.");
static Class* c;
static std::array<MemFunc, 1 + sizeof...(MemFuncs)> mfs;
static void prep(Class& cls, MemFunc mem, MemFuncs... mems) { c = &cls; mfs = { mem, mems... }; }
static void clean() { c = nullptr; for (auto& m : mfs) { m = nullptr; } }
// Registered functions are wrapped by index, with index specified as a template parameter to match empty parameter list.
template<size_t N = 0, bool B = (N < mfs.size())>
static void call() {
static_assert(B, "Index must be a valid index for mfs.");
return (c->*mfs[N])();
}
// Constructor is provided for convenience of creation, to effectively tie prep() to deduction guide.
// Note that it operates on static members only.
// Convenient, but likely confusing. Primarily used because instantiation & preparation get really repetitive otherwise.
MultiCaller(Class& cls, MemFunc mem, MemFuncs... mems) { prep(cls, mem, mems...); }
// Default constructor is required if we provide the above hax ctor.
MultiCaller() = default;
};
template<typename MemFunc, typename Class, typename... MemFuncs> Class* MultiCaller<MemFunc, Class, MemFuncs...>::c = nullptr;
template<typename MemFunc, typename Class, typename... MemFuncs> std::array<MemFunc, 1 + sizeof...(MemFuncs)> MultiCaller<MemFunc, Class, MemFuncs...>::mfs = {nullptr};
It can be used by type alias as before, or the "hax ctor" can be used to couple it to a deduction guide like so:
std::cout << "\nMulti-registration caller, by type alias:\n";
using MyMultiCaller = MultiCaller<decltype(&HasMemberFunction::memfunc), HasMemberFunction, decltype(&HasMemberFunction::funcmem)>;
MyMultiCaller::prep(hmf, &HasMemberFunction::memfunc, &HasMemberFunction::funcmem);
takesVoidFuncPtr(&MyMultiCaller::call<0>); // memfunc
takesVoidFuncPtr(&MyMultiCaller::call<1>); // funcmem
MyMultiCaller::clean(); // Not strictly necessary, but may be useful once the callback will no longer be called.
// Or...
std::cout << "\nMulti-registration caller, via hax ctor:\n";
MultiCaller mclr(hmf, &HasMemberFunction::memfunc, &HasMemberFunction::funcmem);
takesVoidFuncPtr(&mclr.call<0>); // memfunc
takesVoidFuncPtr(&mclr.call<1>); // funcmem
mclr.clean(); // Not strictly necessary, but may be useful once the callback will no longer be called.
Note that in all cases, this has all the caveats of static members. In particular, since the binding relies on the static class members and isn't contained within the wrapper function itself, modifying the members after a callback is passed will immediately change the results of calling said already-passed callback.
std::cout << "\nBut alas:\n";
MyCaller::prep(hmf, &HasMemberFunction::memfunc);
DelayedCaller dc(&MyCaller::call);
dc.callIt(); // Output: "-->Inside instance.memfunc()<--"
std::cout << "Changing the registered instance will...\n";
HasMemberFunction hmf2("spinstance");
MyCaller::c = &hmf2;
dc.callIt(); // Output: "-->Inside spinstance.memfunc()<--"
You can see the different variants here, on Compiler Explorer.
In C++03, when you were to wrap a bunch of C functions in a class to create an 'auto object', you had to customize the object to the type of functions it encapsulated. As an example, to wrap a windows file HANDLE, you needed to call CloseHandle() in the destructor and CreateFile() in the constructor. The constructor would need to mimic the function signature of the CreateFile() function, sans the file HANDLE variable (since it's being managed).
Anyway, what I'd like to know is if it's possible to use the new features of C++11 to create a single generic class that can be used to wrap any type of resource by only providing an implementation for creation and deletion?
One problem I foresee is that the creation function, such as noted above with CreateFile(), can taken any number of parameters. Is there a way to auto-magically generate a templated constructor that mimics the signature of the function? Variadic Parameters come to mind, but I have not yet used them.
Has anyone tried writing something like this?
EDIT: Some code to help illustrate (pseudo):
template<typename Res, FunctionPtrToCreatorFunc Func, typename... Arguments>
class creator
{
public:
operator()(Res &r, Arguments... Args)
{
Func(r, /*use args?*/ Args); // Allocate resource, ie. CreateFile(r, args)
}
};
template<typename Res, FunctionPtrToDeleterFunc Func>
class deleter
{
operator()(Res &r)
{
Func(r); // delete the resource, ie. CloseHandle(r)
}
};
Then this will be the implementation of my super auto object:
template<typename Res, typename Creator, typename Deleter>
class auto_obj
{
public:
auto_obj(/*somehow copy Args from Creator class?*/)
{
Creator(_res, /*args?*/);
}
~auto_obj()
{
deleter(_res);
}
Res _res;
};
Yes, this has a similar structure to shared_ptr or unique_ptr, but instead the constructor will be the one that creates the resources by developer written creator and deleter classes. I have a feeling that std::bind may play a role in this, but I have never used it.
Here is a stab at it:
#include <utility>
#include <type_traits>
#include <cstddef>
A more friendly way to wrap up a function. I move the signature boilerplate to this template, instead of messing up the actual RAII class below. This also allows full fledged function objects to be used, as well as functions, in the RAII class below:
template< typename FuncSig, FuncSig func >
struct Functor {
template<typename... Args>
auto operator()(Args&&... args) const
-> decltype( func(std::forward<Args>(args)...) )
{ return ( func(std::forward<Args>(args)...) ); }
};
One operation that is needed for more than basic functionality is the ability to "null" a handle, allowing invalid handles to exist, and allowing handles to be moved around. Zeroer is my default function object for "null"ing a handle:
struct Zeroer {
template<typename T>
void operator()( T& t ) const {
t = 0;
}
};
RAII_handle herself. You pack the creation and destruction signatures into it, and it forwards construction to the underlying data. .close() lets you close the RAII_handle early, which is a common requirement in practice. You access the underlying data via operator* or operator->, and while this makes it look pointer-like, RAII_handle does not obey pointer semantics. It is a move-only type.
template< typename T, typename Creator, typename Destroyer, typename Nuller=Zeroer >
struct RAII_handle {
RAII_handle( std::nullptr_t ):
data()
{
Nuller()(data);
}
RAII_handle( RAII_handle const& ) = delete;
RAII_handle( RAII_handle && o ):data(std::move(o.data)) {
Nuller()(o.data);
}
RAII_handle& operator=( RAII_handle const& ) = delete;
RAII_handle& operator=( RAII_handle && o ) {
data = std::move(o.data);
Nuller()(o.data);
return *this;
}
template<typename... Args>
RAII_handle( Args&&... args ):
data( Creator()(std::forward<Args>(args)...) )
{}
auto close()->decltype( Destroyer()(std::declval<T&>()) ) {
auto retval = Destroyer()(data);
Nuller()(data);
return retval;
}
~RAII_handle() {
close();
}
T& get() { return data; }
T const& get() const { return data; }
T& operator*() { return get(); }
T const& operator*() const { return get(); }
T* operator->() { return &get(); }
T const* operator->() const { return &get(); }
private:
T data;
};
Now, some test code. My file handles will be unsigned char, and opening/closing will simply test if things are not working right.
#include <iostream>
typedef unsigned char HANDLE;
HANDLE CreateFile( char const* name ) {
std::cout << name << "\n";
return 7;
}
bool CloseFile( HANDLE h ) {
if (h) {
--h;
std::cout << (int)h << "\n";
return true;
} else {
std::cout << "already closed\n";
return true;
}
}
Once you have your open/close functions or function objects, here is how you make the type of the FileHandle:
typedef RAII_handle< HANDLE, Functor< HANDLE(*)( char const* ), CreateFile >, Functor< bool(*)(HANDLE), CloseFile > > FileHandle;
You can support entire overload sets by simply creating a function object that forwards to a fixed function name, instead of to a fixed function pointer. Basically take Functor above, remove the template signature and pointer, and replace the use of func with actual use of your function name.
Suddenly your function object represents not calling one function, but calling an entire overload set.
Fancier work can even support multiple functions, allowing one function object to support calling either CreateFile or CreateFileEx depending on what arguments are passed in.
And here is our trivial test code:
int main() {
FileHandle bob("hello.txt");
HANDLE value = *bob; // get the HANDLE out of the FileHandle
bob.close(); // optional, to close early
}
Requirements: your CloseFile must accept Nuller()(std::declval<T&>()) and not behave badly. The default Nuller()(...) just assigns zero to your T, which works for many handle types.
It supports move semantics, allowing you to return these from a function, but I didn't include a Copier argument (which I'd expect would be required for any RAII objects that can be copied).
Live example with very slightly different code.
Even though I fear that you will tell me that this topic was covered several time, I dare to ask it, since I was not able to generate a solution. Probably I was just looking for the wrong thing...
Assume that I have a function which receives a "mode" from some external function. Depending on the mode, the function will call different member functions of the same object. This works well for me with member function without any argument, but I did not find out how to extend it to members with arguments. In the real world application, the arguments are not int/float but a more complex classes and the call is nested inside different loops, so I would need to put switch statements several times which I consider ugly.
Question A: Is it possible to easily add support for member functions with arguments based on the existing design? If yes, how does one do that? If possible without external libraries...
Question B: Is this a completely wrong/bad approach? How would I do it better?
Thanks a lot for your help and explanations.
Chris
header excerpt:
typedef void (Object::*memberFunction)();
class Object
{
void memberFnNoArg();
void memberFnWithIntArg(int arg);
void memberFnWithFloatArg(float arg);
}
cpp excerpt:
void function()
{
int mode = getModeFromSomewhere();
int intArg = 33;
float floatArg = 66.6;
switch(mode)
{
case 1:
process(&Object::memberFnNoArg);
break;
case 2:
process(&Object::memberFnWithIntArg, ???); // how can I pass arg?
break;
case 3:
process(&Object::memberFnWithFlaotArg, ???); // how can I pass arg?
break;
default:
// do nothing;
}
}
void process(Object::memberFunction func)
{
Object object;
// loops, called several times, ...
(object.*func)(); // how do I handle different arguments?
}
Wrapping the algorithm in a functor is the right approach, and std::function is a nice functor provided by the Standard library.
But using boost::bind or even std::bind, as suggested by Tomek, is really ugly IMO, and rapidly gets out of control when binding multiple arguments.
If you have a recent compiler you can use a lambda instead, which makes Tomek's example look like:
std::function<void(Object*)> f =
[](Object* const that){ that->memberFnNoArg(); };
int int_value = 22;
std::function<void(Object*)> f2 =
[int_value](Object* const that){ that->memberFnIntArg(int_value); };
Object o;
f(&o);
f2(&o);
There are a few characters to set up the lambda, but the member access syntax is extremely natural and it's obvious how you make changes.
Of course, you can make the parameter a reference to the object if you really want, but I prefer pointers here.
Have a look at std::function and std::bind, they seem to fit perfectly what you need.
EDIT:
std::function<void(Object &)> f = &Object::memberFnNoArg;
std::function<void(Object &)> f2 = std::bind(&Object::memberFnWithIntArg, _1, 22);
Object o;
f(o);
f2(o);
should work out of a box as far as I remember.
Is this what you need?
You could use a varadic template function:
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
Here is a full example:
#include <iostream>
struct Object
{
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
};
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
int main()
{
process(&Object::memberFnNoArg);
process(&Object::memberFnWithIntArg,5);
process(&Object::memberFnWithFloatArg,2.7F);
return 0;
}
One way I see around this would be to use a variable arguments (pretty much like printf, sprintf does it). (Or maybe with stdc libraries, passing a list of different types.)
The reason is, that the argument list is part of the function pointer type, so you'd essentially need a process function with variable arguments and then the memberFunction probably needs to be one of that type too.
Below is a plain (non member) sample of how to pick up variable arguments (member functions would essentially work the same). See stdarg.h.
typedef void (*var_function)(int typearg, ...);
void print_arg(int typearg, ...)
{
va_list ap;
int i;
va_start(ap, typearg);
if (typearg==1) { // int
int i= va_arg(ap, int);
printf("%d ", i);
}
else
if (typearg==2) { // float
float f= va_arg(ap, float);
printf("%f ", f);
}
else
if (typearg==3) { // char *
char *s= va_arg(ap, char *);
printf("%s ", s);
}
....
va_end(ap);
}
// calling function with different types
int main()
{
print_arg(1, 999);
print_arg(2, 3.1415926);
print_arg(3, "Hello");
....
process(print_arg, 3, "via pointer);
Sounds like packaged_task. Also check out Tomek's suggestion.
Though IRL I'd go ahead asking lots of questions on why you need it in the first place. Possibly your work could be better covered using std::future or other higher level facility,
Can't each function (memberFn**) be a member of argument classes ?
class BaseArg
{
virtual void Fn() = 0;
};
class IntArg : public BaseArg
{
void Fn();
};
class FloatArg : public BaseArg
{
void Fn();
};
void function()
{
int mode = getModeFromSomewhere();
BaseArg* pArg;
if ( mode ... ){
pArg = new IntArg( 33 );
}
else {
pArg = new FloatArg( 66.6 );
}
pArg->Fn(); // Call the right function without a switch
// and without knowing the arguments
}
Same as other answers, but to show for member methods:
#include <iostream>
class Object
{
public:
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
bool memberFnWithBoolReturn(int)
{
return true;
}
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args);
// overload process
template <typename... Args>
bool process(bool (Object::*func)(Args...),Args... args);
};
template <typename... Args>
void process( void (Object::*func)(Args...),class Object* obj,Args... args)
{
(obj->*func)(args...);
}
template <typename... Args>
bool process( bool (Object::*func)(Args...),class Object* obj,Args... args)
{
return ((obj->*func)(args...)) ;
}
int main()
{
Object object;
process(&Object::memberFnNoArg,&object);
process(&Object::memberFnWithIntArg,&object,5);
process(&Object::memberFnWithFloatArg,&object,2.7F);
// overloaded process
printf("%d\n",process(&Object::memberFnWithBoolReturn,&object,1));
return 0;
}
If the function pointer embedded in a boost::bind return object is NULL/nullptr/0, I need to take action other than calling it. How can I determine if the object contains a null function pointer?
Addenda
I don't believe I can use and compare boost::functions as the boost::bind return object is used with varying call signatures in a template function.
Simplified example:
template <typename BRO>
Retval do_stuff(BRO func, enum Fallback fallback)
{
if (func == NULL)
{
return do_fallback(fallback);
}
else
{
return use_retval(func());
}
}
do_stuff(boost::bind(FuncPtrThatMightBeNull, var1, var2), fallback);
Solution
Since the arity of the function in the callee does not change, I can "cast" the bind return object into a boost::function and call .empty()
Retval do_stuff(boost::function<Retval()> func, enum Fallback fallback)
{
if (func.empty())
return do_fallback(fallback);
else
return use_retval(func());
}
You can either bind to a dummy function:
void dummy() { /* has differing behaviour */ }
// ...
boost::bind(&dummy)();
... or, assuming you're using Boost.Bind together with Boost.Function, return a default constructed function object and check for empty() before calling it:
typedef boost::function<void (void)> F;
F create() { return F(); }
void use() {
F f = create();
if(f.empty()) {
/* ... */
}
}
Regarding the update:
I still don't see what the problem with binding to a different function like the following would be:
template <typename BRO>
Retval do_stuff(BRO func)
{
return func();
}
if(funcPtr) {
do_stuff(boost::bind(&use_retval, boost::bind(funcPtr, a, b)));
} else {
do_stuff(boost::bind(&do_fallback, fallback));
}
If you'd want to move that handling out of the calling code, you could emulate variadic template function to support variable arities:
template<class R, class T1>
boost::function<R (T1)>
bind_wrap(R (*fnPtr)(), T1& t1, Fallback fallback) {
if(fnPtr) return boost::bind(&use_retval, boost::bind(funcPtr, t1));
else return boost::bind(&do_fallback, fallback);
}
template<class R, class T1, class T2>
boost::function<R (T1, T2)>
bind_wrap(R (*fnPtr)(T1, T2), T1& t1, T2& t2, Fallback fallback) {
if(fnPtr) return boost::bind(&use_retval, boost::bind(funcPtr, t1, t2));
else return boost::bind(&do_fallback, fallback);
}
// ... etc. for all needed arities
do_stuff(bind_wrap(funcPtr, var1, var2, fallback));
... or you use the approach above to generate boost::function<> objects or your own wrappers and check for functor.empty() or similar in do_stuff().
I'd create a wrapper object to do this. Something like the following
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
int aFunction(int i, int j)
{
std::cout<<"In a Function"<<std::endl;
return i+j;
}
struct DefaultingFromFnPtr : public boost::function< int(int,int) >
{
explicit DefaultingFromFnPtr( int(*fn)(int,int) ) : fn_(fn) {}
int operator()(int i, int j) const
{
if (fn_!=NULL) return fn_(i, j);
return 7;
}
int(*fn_)(int,int);
};
template<typename T>
void do_stuff( T t )
{
std::cout<<"RETURNED "<<t()<<std::endl;
}
int main( int argv, const char** argc)
{
int(*mightBeNullFnPtr)(int,int) = NULL;
if( argv>1)
{
mightBeNullFnPtr = & aFunction;
}
int var1 = 10;
int var2 = 20;
do_stuff( boost::bind( DefaultingFromFnPtr( mightBeNullFnPtr ), var1, var2 ) );
}
Compile this and run it with no arguments and it sets mightBeNullFnPtr to NULL and calls do_stuff with a wrapper class, and so prints out 7. Run it with an argument and it will set mightByNullFnPtr to aFunction and calls do_stuff with that, printing out 30.
If you want more genericity you will need to template the DefaultingFromFnPtr wrapper class, but that should be pretty easy to do.
I'm pretty sure calling boost::bind with a null pointer (= the creation of the bind object) should be considered undefined behavior, even if the crash only happens when calling it.
You're going to have to hack boost.
boost::bind returns unspecified-n-n. The only thing valid to do with these classes is operator(). The only other thing you know is that they are copy constructable, and have a typedef for result_type (which, by the way, means you don't need a template for result type).
You want something else - so you'll need to find the definition of unspecified-n-n in boost (there maybe several), hack them to have a is_null() member function which checks for the conditions you want, then call that as your test.
This is, of course, assuming you are certain you'll always get a boost::bind'ed object in your template function. If someone tries passing in a regular function pointer, it won't compile. Working around this will require some template magic.