So for this function:
template<typename T>
T popObject(ScriptObject obj) { //Preforms a cast from void* on each to its type.
assert(obj.getType() == std::type_index(typeid(T))); //Ensure type Safety.
return obj.get<T>();
}
template <typename C, typename...Args>
void bind(const char* name, C* context, void(C::* function)(Args...)) {
std::vector<std::type_index> arguments = { std::type_index(typeid(Args))... };
auto functor = [](void* func,void* contex, std::vector<ScriptObject> stack) {
std::size_t idx = 0;
//Call class context -> function (Args...)
};
_functions[name] = new BoundFunction(functor, void_cast(function), context, arguments);
}
I'm unsure of the syntax for calling the member function.
Iv tried:
union MF{
void(C::* pf)(Args...);
void* p;
} mf;
mf.p = func;
contex->*(mf.pf)(popObject<Args>(stack[idx++])...);
Which does not compile, Stating: "Does not evaluate to a function taking 1 Arguments."
Tried std::invoke, But I Don't know how to Specify the Member function Signature for arg1.
So If i have a reference to the member function, And a reference to the instance of the class, As well as the template information to Derive type information. How do I call the Classes member function?
Thanks #Igor Tandentnik
Final Solution was:
(static_cast<C*>(ctx)->*(mf.pf))(popObject<Args>(stack[idx++])...);
As Igor pointed out, it needed to be ->* instead of .*, and added parenthesis, as -> has a lower priority then the Function call operator.
Also, thanks #TheFloatingBrain for pointing out the extra static_cast
Related
I am working on a small signal dispatcher implementation and I have hit a problem I cannot seem to solve. I tried to find info on the internet but came up short on this specific problem.
I am trying to give a function template a function pointer to an overloaded bound member function, via a template parameter. The function is called "connect". I am using auto for the template parameter which holds the function pointer but the compiler says "no matching overloaded function found" when I try to call the function.
I have implemented a second connect function where I specify the function pointer type in the template parameter (instead of using auto) and with this function it works.
Maybe someone can explain to me, why the first connect function doesn't work for the overloaded member function. I am probably missing something about template parameter deduction but I cannot find out what it is.
Here is the code (C++ 17 and above):
struct EventHandler
{
EventHandler() = default;
void handleEventOverloaded(int x)
{
z = x;
}
void handleEventOverloaded(float x)
{
z = static_cast<int>(x);
}
void handleEvent(float x)
{
z = static_cast<int>(x);
}
int z = 0;
};
class Dispatcher
{
public:
template <typename EventType, auto Function, typename InstanceType>
auto connect(InstanceType& instance)
{
auto f = Function;
int x = 0;
}
template <typename EventType, void(EventHandler::* Function)(float), typename InstanceType>
auto connect2(InstanceType& instance)
{
auto f = Function;
int x = 0;
}
};
int main()
{
Dispatcher dispatcher{};
EventHandler evHandler{};
dispatcher.connect<float, &EventHandler::handleEventOverloaded>(evHandler); //Error: no matching overloaded function found
dispatcher.connect<float, &EventHandler::handleEvent>(evHandler); //OK: bound non-overloaded member function
dispatcher.connect2<float, &EventHandler::handleEventOverloaded>(evHandler); //OK: bound overloaded member function
//Test if the function pointer works
void(EventHandler:: * evHandlerFunc)(float) = &EventHandler::handleEventOverloaded;
((&evHandler)->*evHandlerFunc)(5.5f);
return 0;
}
I think this is what you are searching for:
For pointers to members, the argument has to be a pointer to member expressed as &Class::Member or a constant expression that evaluates to null pointer or std::nullptr_t (since C++11) value.
Here is the full Template parameters and template arguments page from cppreference.com if you want to read it yourself.
This is a template function that takes a pointer (or a pointer like object) and a member function:
template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
return (ptr->*func)();
}
If works when used with ordinary pointer:
struct C
{
int getId() const { return 1; }
};
C* c = new C;
example(c, &C::getId); // Works fine
But it does not work with smart pointers:
std::shared_ptr<C> c2(new C);
example(c2, &C::getId);
Error message:
error: C2296: '->*' : illegal, left operand has type 'std::shared_ptr<C>'
Why? and How to make something that works with both?
std::shared_ptr doesn't support pointer-to-member access operator (i.e. ->* and .*). So we can't invoke member function pointers with ->* on it directly. You can change the invoking syntax to use operator* and operator.*, which works for both raw pointers and smart pointers.
template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
return ((*ptr).*func)();
}
LIVE
std::shared_ptr doesn't have an operator->*. You have two main options:
You could write an overload which takes a std::shared_ptr (maybe one for std::unique_ptr as well):
template <typename T, typename MemberFunctor>
int example(std::shared_ptr<T> ptr, MemberFunctor func )
{
return ((ptr.get())->*func)();
}
However, I would suggest just making example take a reference to T and calling func on it. example doesn't need to know anything about how the pointer is stored, so it shouldn't require all of these extra overloads.
template <typename T, typename MemberFunctor>
int example(T&& t, MemberFunctor func )
{
return (std::forward<T>(t).*func)();
}
Now if you have a std::shared_ptr<T>, you'd call example like:
example(*my_shared_ptr, my_func);
std::shared_ptr doesn't overload operator ->*. You may add a overload:
template <typename Ptr, typename MemberFunctor>
int example(std::shared_ptr<Ptr> ptr, MemberFunctor func )
{
return (ptr.get()->*func)();
}
I've been trying to come up with a templated function that generalizes the bounce procedure when dealing with C APIs that use function pointer callbacks.
I've mostly figured it out and have a working system, but I'm wondering if there is a way to clean up the final step.
Imagine you have an API that takes a function pointer and a user data pointer. You want to use an instance method as the callback target. This requires a "bounce" function that reinterprets the user data pointer as an instance pointer and calls the method with the rest of the arguments.
The following example code works:
#include <cstdio>
class Foo {
public:
Foo(int val) : val_(val) { }
void baz(int v) const
{
printf("baz %d\n", v + val_);
}
private:
int val_;
};
// Templated bounce function
template<class T, class Method, Method m, class Ret, class ...Args>
static Ret bounce(void *priv, Args... args)
{
return ((*reinterpret_cast<T *>(priv)).*m)(args...);
}
#define BOUNCE(c, m) bounce<c, decltype(&c::m), &c::m>
// Callback simulator
void call_callback(void (*func)(void *, int), void *priv, int v)
{
if (func) {
func(priv, v);
}
}
// Main Entry
int main()
{
Foo bar(13);
call_callback(&bounce<Foo, decltype(&Foo::baz), &Foo::baz>, &bar, 10);
call_callback(&BOUNCE(Foo, baz), &bar, 11);
return 0;
}
Basically I'm looking for a way to clean up the usage. The macro works but I'm trying to instead find some type of helper function that can just take a method pointer parameter like &Foo::baz and deduce all the parameters. Something like a bounce_gen(&Foo::baz) that would return a pointer to the actual bounce function.
It has been a fun exercise, but I can't quite get the last piece.
The type of a member function pointer contains the class type and the function signature. So, you can let template function argument deduction handle this for you:
template<class T, class Method, class ...Args>
static auto bounce(Method T::*func, T* priv, Args... args) -> decltype((priv->*m)(args...))
{
return (priv->*m)(args...);
}
More convenient might be to either use std::bind or a lambda to completely hide the fact that it is a member function call:
template<class Func, class ...Args>
static auto bounceCallable(Func func, Args... args) -> decltype(func(args...))
{
return func(args...);
}
And you would call it like this:
call_callback([&bar](int v){bar.baz(v);}, 11);
With a lambda, you have a syntax nicer than with std::bind, but it comes at the cost of having to repeat the signature.
I'm going through some template sample code and there's one thing I don't get.
Take a template methode:
template<class Seq, class T, class R>
void apply(Seq &sq, R(T::*f)() const) {
typename Seq::iterator it = sq.begin();
while(sq.end() != it) {
((*it++)->*f)();
}
}
A sample class:
class MyClass {
public:
MyClass() {}
void doSomething() const {
std::cout << "doing stuff..." << std::endl;
}
};
And the test code:
void testMyClass() {
vector<MyClass*> v;
for(size_t i = 0; i < 5; ++i) {
v.push_back(new MyClass());
}
// call a member methode on all elements in container
apply(v, &MyClass::doSomething);
}
I would be grateful if someone could explain me what is that class R for, as defined in the template definition?
class R refers to the return type of the function pointer being passed to the function apply. It is automatically deduced from the actually passed function pointer type, so you never really need to care about it when calling apply.
The implementation of apply discards the return value of the function, so you could simply force the passed function to return void:
template<class Seq, class T>
void apply(Seq &sq, void(T::*f)() const) {
typename Seq::iterator it = sq.begin();
while(sq.end() != it) {
((*it++)->*f)();
}
}
However, now you restrict the call site to only pass such function pointers. Sadly, a pointer to a function which returns something isn't implcitly convertible to one which doesn't, although it would be pretty "intuitive".
So when you take a function pointer as an argument, and you don't care about the return type, it's better to accept "any" return type than "none".
class R in the template is used to deduce the return type of the function. In your case, it is deduced to be of type void.
I am currently in the process of writing a method execution queue in C++x0. I have implemented and verified the basic queue mechanism but want to amend it with an option to have push() automatically remove all previous calls to a specific method:
queue.push(this, &Obj::foo, 1);
queue.push(this, &Obj::foo, 2);
queue.push(this, &Obj::foo, 3);
should be the same as merely calling
queue.push(this, &Obj::foo, 3);
My code thus far looks like this:
Queue.h:
#pragma once
#include <functional>
#include <vector>
using std::vector;
using std::function;
using std::bind;
class Queue
{
private:
struct functioncall {
std::function<void()> call;
};
vector<functioncall> queue;
public:
Queue();
~Queue();
template<typename T, typename F, typename... Args>
int push(T, F , Args... args);
int pop();
bool empty();
size_t size();
};
template<typename T, typename F, typename... Args>
int Queue::push(T instance, F func, Args... args)
{
functioncall newelem = { bind(func, instance, args...) };
queue.push_back(newelem);
return queue.size();
}
Queue.cpp:
#include "Queue.h"
Queue::Queue() : queue()
{
}
Queue::~Queue()
{
delete &queue;
}
int Queue::pop()
{
if(!queue.empty())
{
queue.front().call();
queue.erase(queue.begin());
return queue.size();
}
return 0;
}
bool Queue::empty()
{
return queue.empty();
}
size_t Queue::size()
{
return queue.size();
}
I have already prepared the vector queue to take a struct in wich I want to not only save the result of std::bind but also the pointer to the method being called so I can look for that pointer and remove the old entries.
The issue is that the functions passed to push() can take an arbitrary amount of arguments. Is there a generic pointer type (it doesn't have to be executable, just be the same when I repeatedly push the same function to the queue) that can do that?
Per 5.2.10p10, you can cast a pointer to member function T::*(A1, A2, ...) to another pointer to member function type U::*(B1, ...) and back with no loss of information; std::less can compare pointers to member functions so by casting to a dummy pointer-to-member type void (Impl::*)() you can compare pointer to member functions with the same signature.
However, it is not guaranteed that pointer to member functions with different signatures will compare different when cast to the same pointer to member type, so you will need to encode the signature in your comparable type. typeid will work here:
auto key = std::make_pair(&typeid(F), reinterpret_cast<void (Queue::*)()>(func));
This assumes that F is indeed a pointer to member function; if the user attempts to pass some other callable object then this will break.
std::function::target<>() can be used to check wrapped function type:
template <class F> bool is_same_call(const functionalcall& prevCall, F newCall)
{
const F* pf = prevCall.call.target<F>();
return pf ? *pf == newCall : false;
}
Note that std::function::target() will return nullptr if function wrapped with std::function object has type different from F.