Pointer to overloaded bound-member function as template argument - c++

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.

Related

How to call a class member function from 2 void pointers

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

Passing function as template argument to a member function

I am trying to pass function as template argument to a function in a class, but there is some mistake. The code is giving an error error: missing template arguments before 'obj'. How can I fix this so that it compiles?
#include<iostream>
double sum_fun(const double &a, const double &b)
{ std::cout<<a+b<<"\n"; }
template <typename F>
class B
{
public:
void fb()(F f1)
{
f1(10.1,10.2);
}
};
int main()
{
B obj(sum_fun); //error
obj.fb(); //error
return 0;
}
There is a misunderstanding of how classes work.
int main()
{
B obj(sum_fun); // calls B constructor with parameter `sum_fun`
obj.fb(); // calls member function B::fb() with no parameters
return 0;
}
Both lines raise an error as
Your class has no constructor which takes a single parameter.
void fb()(F f1) is illegal syntax. To declare a member function, use only one set of parentheses: either void fb() or void fb(F f1). The latter is incorrect in our case, as your member function call obj.fb() passes no parameters.
To fix this, write up a constructor, store the function as a member variable, and use that variable in the function fb().
template <typename F>
class B
{
public:
// constructor, initialises member `m_func` through member initialisation
B(F func) : m_func(func) {}
void fb()
{
m_func(10.1,10.2);
}
private:
F m_func;
};
In C++17, thanks to automatic template deduction, no errors are now emitted. But in lower standards (e.g. C++11), template deduction is lacking and thus, the full templated type needs to be specified when declaring obj.
So in standards below C++17, the main function should be:
int main()
{
// C++11: using a function pointer to denote type
B<double(*)(const double&, const double&)> obj(sum_fun);
// ok in C++17, looks cleaner too
// B obj(sum_fun);
obj.fb();
return 0;
}
Here, double(*)(const double&, const double&) is a function pointer, i.e. a pointer to a function which returns a double and takes two parameters, both of type const double&. Function pointers may be considered as a type, which satisfies the template (template<typename F>).
Just like we do std::vector<int> and std::vector<double>, we can also do std::vector<double(*)(const double&, const double&)> to denote a vector of functions returning double and taking const double& as parameters.
And by the way, sum_fun also raises a warning: nothing is returned even though the return type is double... better specify void as the return type instead.
C++11 Demo
C++17 Demo
Is it possible to pass function as argument directly to B::fb() instead of creating constructor B::B(F) and storing in local variable?
Certainly.
#include <iostream>
void sum_fun(const double& a, const double& b)
{
std::cout << a+b << "\n";
}
template <typename F>
class B
{
public:
void fb(F func)
{
func(10.1,10.2);
}
};
int main()
{
B<void(*)(const double&, const double&)> obj;
obj.fb(sum_fun);
return 0;
}
Note that the member function fb now takes a single parameter func, which we then call. Note also that in C++17, we now can't instantiate the obj with B obj; because this would be ambiguous and the template can't be deduced automatically. Instead, we need to specify the full type B<void(*)(const double&, const double&)>.
However, a recommended alternative over function pointers is to use std::function, which is more versatile and offers a more readable syntax. (std::function Demo)
In C++17 you're allowed to use auto in template paramter list:
template <auto F>
class B
{
public:
void fb()
{
F(10.1,10.2);
}
};
You can then do B<sum_fun>:
int main()
{
B<sum_fun> obj{};
obj.fb();
return 0;
}

Need clarification on C++ template format

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.

std::is_function does not recognize template argument as function

I am passing a pointer to function into a function template:
int f(int a) { return a+1; }
template<typename F>
void use(F f) {
static_assert(std::is_function<F>::value, "Function required");
}
int main() {
use(&f); // Plain f does not work either.
}
But the template argument F is not recognized by is_function to be a function and the static assertion fails. Compiler error message says that F is int(*)(int) which is a pointer to function. Why does it behave like that? How can I recognize the function or pointer to function in this case?
F is a pointer to function (regardless of whether you pass f or &f). So remove the pointer:
std::is_function<typename std::remove_pointer<F>::type>::value
(Ironically, std::is_function<std::function<FT>> == false ;-))

Nested bind expressions

This is a followup question to my previous question.
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&& c) { return c();}
template <class C> void func_wrapper(C&& c) { func( std::bind(doit<C>, std::forward<C>(c)) ); }
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
I'm getting a compile errors deep in the C++ headers:
functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind<std::_Mem_fn<int (bar::*)(int)>(bar, int)>’ requested
func_wrapper(foo) is supposed to execute func(doit(foo)). In the real code it packages the function for a thread to execute. func would the function executed by the other thread, doit sits in between to check for unhandled exceptions and to clean up. But the additional bind in func_wrapper messes things up...
At the beginning, please let me introduce 2 key points:
a: When using nested std::bind, the inner std::bind is evaluated first, and the return value will be substituted in its place while the outer std::bind is evaluated. That means std::bind(f, std::bind(g, _1))(x) executes as same as f(g(x)) does. The inner std::bind is supposed to be wrapped by std::ref if the outer std::bind wants a functor rather than a return value.
b: The r-value reference cannot be correctly forwarded to the function by using std::bind. And the reason has already been illustrated in detail.
So, let's look at the question. The most importance function here might be func_wrapper which is intended to perform 3 purposes:
Perfect forwarding a functor to doit function template at first,
then using std::bind to make doit as a closure,
and letting func function template execute the functor returned by std::bind at last.
According to point b, purpose 1 cannot be fulfilled. So, let's forget perfect forwarding and doit function template has to accept a l-value reference parameter.
According to point a, purpose 2 will be performed by using std::ref.
As a result, the final version might be:
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&/*&*/ c) // r-value reference can't be forwarded via std::bind
{
return c();
}
template <class C> void func_wrapper(C&& c)
{
func(std::bind(doit<C>,
/* std::forward<C>(c) */ // forget pefect forwarding while using std::bind
std::ref(c)) // try to pass the functor itsself instead of its return value
);
}
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error disappears
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error disappears
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
But, if you really want to achieve purpose 1 and 2, how? Try this:
#include <functional>
#include <iostream>
void foo()
{
}
struct bar {
void operator()() {}
void dosomething() {}
};
static bar b;
template <typename Executor>
void run(Executor&& e)
{
std::cout << "r-value reference forwarded\n";
e();
}
template <typename Executor>
void run(Executor& e)
{
std::cout << "l-value reference forwarded\n";
e();
}
template <typename Executor>
auto func(Executor&& e) -> decltype(e())
{
return e();
}
template <bool b>
struct dispatcher_traits {
enum { value = b };
};
template <typename Executor, bool is_lvalue_reference>
class dispatcher {
private:
static void dispatch(Executor& e, dispatcher_traits<true>)
{
run(e);
}
static void dispatch(Executor& e, dispatcher_traits<false>)
{
run(std::ref(e));
}
public:
static void forward(Executor& e)
{
dispatch(e, dispatcher_traits<is_lvalue_reference>());
}
};
template <typename Executor>
void func_wrapper(Executor&& e)
{
typedef dispatcher<Executor,
std::is_lvalue_reference<Executor>::value>
dispatcher_type;
func(std::bind(&dispatcher_type::forward, std::ref(e)));
}
int main()
{
func_wrapper(foo); // l-value
func_wrapper(b); // l-value
func_wrapper(bar()); // r-value
func_wrapper(std::bind(&bar::dosomething, &b)); // r-value
func_wrapper([](){}); // r-value
}
Let me explain some points:
To reduce lots of return statements, changing functor signature from int() to void().
The 2 run() function templates are used to check whether the original functor parameter is perfect forwarded or not.
dispatcher_traits is going to map bool constant to type.
You'd better name dispatcher::forward to differ from dispatcher::dispatch or you have to invoke std::bind template with dispatcher::forward's signature.
Looking at this the second time now, and I think I have a plausable explanation for the first error you are seeing.
In this case, it's more helpful to look at the complete error and the template instantiations that lead up to it. The error printed by my compiler (GCC 4.4), for example, ends with the following lines:
test.cpp:12: instantiated from ‘decltype (c()) func(C&&) [with C = std::_Bind<int (*(int (*)()))(int (&)())>]’
test.cpp:16: instantiated from ‘void func_wrapper(C&&) [with C = int (&)()]’
test.cpp:22: instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
Now looking at this bottom-up, the actual error message seems correct; the types the compiler has deduced are incompatible.
The first template instantiation, at func_wrapper, clearly shows what type the compiler has deduced from the actual parameter foo in func_wrapper(foo). I personally expected this to be a function pointer, but it is in fact a function reference.
The second template instantiation is hardly readable. But messing around with std::bind a bit, I learned that the format of the textual representation GCC prints for a bind functor is roughly:
std::_Bind<RETURN-TYPE (*(BOUND-VALUE-TYPES))(TARGET-PARAMETER-TYPES)>
So tearing it apart:
std::_Bind<int (*(int (*)()))(int (&)())>
// Return type: int
// Bound value types: int (*)()
// Target parameter types: int (&)()
This is where the incompatible types start. Apparently, even though c in func_wrapper is a function reference, it turns into a function pointer once passed to std::bind, resulting in the type incompatibility. For what it's worth, std::forward doesn't matter at all in this case.
My reasoning here is that std::bind only seems to care about values, and not references. In C/C++, there's no such thing as a function value; there's only references and pointers. So when the function reference is dereferenced, the compiler can only meaningfully give you a function pointer.
The only control you have over this is your template parameters. You will have to tell the compiler that you're dealing with a function pointer from the start to make this work. It's probably what you had in mind anyways. To do that, explicitly specify the type you want for the template parameter C:
func_wrapper<int (*)()>(foo);
Or the more brief solution, explicitly take the function's address:
func_wrapper(&foo); // with C = int (*)()
I'll get back to you if I ever figure out the second error. :)