Template std::function as class member function C++ - c++

I would like to store a std::function in a class as a member.
I have troubles with below test code when calling a.callMethod() where the method has been set just before with a.setMethod(). The code works fine if I remove the template.
I have tried to debug with a function callMethodOutsideClass without success.
Is there a better way to manage that ?
#include <iostream>
#include <vector>
#include <functional>
template<typename T>
struct A
{
A(size_t size, T value) : vec_(size, value), method_(nullptr) {}
void setMethod(const std::function<int(A<T>&)> method) { method_ = method; }
int callMethod()
{
if(method_)
return method_(*this);
else
std::cerr << "method not initialized" << std::endl;
return -1;
}
std::vector<int> vec_;
std::function<int(A<T>& a)> method_;
};
template<typename T>
int callMethodOutsideClass(struct A<T>& a, const std::function<int(A<T>&)> method)
{
return method(a);
}
template<typename T>
int apple(struct A<T>& a)
{
a.vec_[0] += 1;
return 1;
}
template<typename T>
int orange(struct A<T>& a)
{
a.vec_[0] += 2;
return 2;
}
int main()
{
A<int> a(10,4), b(10,4);
std::cout << callMethodOutsideClass(a, &apple) << std::endl;
a.setMethod(&orange);
std::cout << a.callMethod() << std::endl;
std::cout << a.vec_[0] << std::endl;
}
I currently get the following errors :
Foo6.cpp: In function ‘int main()’:
Foo6.cpp:46:47: error: cannot resolve overloaded function ‘apple’ based on conversion to type ‘std::function<int(A<int>&)>’
std::cout << callMethodOutsideClass(a, &apple) << std::endl;
^
Foo6.cpp:48:21: error: no matching function for call to ‘A<int>::setMethod(<unresolved overloaded function type>)’
a.setMethod(&orange);
^
Foo6.cpp:48:21: note: candidate is:
Foo6.cpp:9:7: note: void A<T>::setMethod(std::function<int(A<T>&)>) [with T = int]
void setMethod(const std::function<int(A<T>&)> method) { method_ = method; }
^
Foo6.cpp:9:7: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘std::function<int(A<int>&)>’

A pointer to function is not a std::function<T>. The std::function<T> signature can't be deduced based on the function address given as an argument. In addition, the compiler can't resolve a proper function template specialization to get its address when a conversion to std::function<T> is requested, since the constructor of std::function<T> is a function template as well.
You need to be more explicit:
std::cout << callMethodOutsideClass<int>(a, &apple<int>) << std::endl;
// ^^^^^ ^^^^^
a.setMethod(&orange<int>);
// ^^^^^
Is there any way to deduce templates parameters "easily" ?
You can modify the signature of callMethodOutsideClass in one of two ways:
Option #1:
Disable a type deduction on a std::function<int(A<T>&)> parameter:
template <typename T> struct identity { using type = T; };
template<typename T>
int callMethodOutsideClass(A<T>& a, const typename identity<std::function<int(A<T>&)>>::type method)
{
return method(a);
}
But you'll have to pay for the type-erasure applied by a std::function.
Option #2:
Let the compiler deduce the real type of a functor object given as an argument:
template <typename T, typename F>
int callMethodOutsideClass(A<T>& a, F&& method)
{
return std::forward<F>(method)(a);
}
In both cases you can just say:
callMethodOutsideClass(a, &apple<int>);
// ^^^^^
Note: You still have to pass the address of a concrete function template specialization by providing a list of template arguments &apple<int>. If you want to get away with a simple &address syntax, then the function taking it needs to declare an exact type of that argument:
template<typename T>
int callMethodOutsideClass(A<T>& a, int(*method)(A<T>&))
{
return method(a);
}
callMethodOutsideClass(a, &apple);
or you could help the compiler resolve the proper overload at a call site:
callMethodOutsideClass(a, static_cast<int(*)(decltype(a)&)>(&apple));
...or, you can use a lambda expression defined as follows:
template<typename T, typename F>
int callMethodOutsideClass(struct A<T>& a, F&& method)
{
return std::forward<F>(method)(a);
}
// in C++11:
callMethodOutsideClass(a, [](decltype(a)& x){return apple(x);});
// in C++14:
callMethodOutsideClass(a, [](auto&& x){return apple(std::forward<decltype(x)>(x));});
As far as the setMethod member function is concerned, the things are easier, since the compiler knows exactly that it expects const std::function<int(A<T>&)> method where T is known (not deduced). So basically, you just need to help the compiler to get the address of a function template specialzation you need at the call site:
a.setMethod(&orange<int>);
a.setMethod(static_cast<int(*)(decltype(a)&)>(&orange));

Related

C++ function template type deduction from function parameter fails

I am writing a small signal-slot implementation to learn more about the usage of templates.
I ran into a problem when I want the compiler to deduce the type of a template parameter of a function template from the function's parameter.
Before asking here, I watched several videos (i.e Arthur O'Dwyers 'Template Normal Programming') and read through several articles but i just can't figure out why it isn't working.
I have built a minimal working example:
#include <iostream>
#include <vector>
//Base Event class for passed around events
struct Event
{
virtual ~Event() = default;
Event(int keyCode) : keyCode_{keyCode} {}
int keyCode_;
};
//Event to be passed around
struct KeyPressedEvent final : Event
{
~KeyPressedEvent() { std::cout << "KeyPressedEvent dtor " << std::endl; }
KeyPressedEvent(int keyCode) : Event(keyCode) { std::cout << "KeyPressedEvent param. ctor " << std::endl; }
};
//Class which holds a callback(slot)
struct Window
{
Window(int y) { std::cout << "window param ctor\n"; }
void kpEventHandler(KeyPressedEvent& kpEvent)
{
std::cout << "non-static member staticKpEventHandler() : " << kpEvent.keyCode_ << "\n";
}
};
//Signal which holds connections to callbacks
template<typename Signature> struct Signal;
template<typename Ret, typename ArgType>
struct Signal<Ret(ArgType)>
{
struct Connection
{
using Instance_t = void*;
using Call_t = void(*)(void*, ArgType&&);
//template <typename Type>
Connection(void* instance, Call_t call) :
instance_{instance}, call_{std::move(call)} {}
bool operator==(const Connection& other) const noexcept
{
bool cmpInstance = instance_ == other.instance_;
bool cmpCall = call_ == other.call_;
return cmpInstance && cmpCall;
}
Instance_t instance_;
Call_t call_;
};
std::vector<Connection> connections_;
template<typename C, Ret(C::* func)(ArgType)>
static void call(void* instancePtr, ArgType&& arg)
{
C* instance = static_cast<C*>(instancePtr);
if (instance != nullptr)
{
(instance->*func)(std::forward<ArgType>(arg));
}
}
template<typename C, Ret(C::* func)(ArgType)>
void connect(C& instance)
{
connections_.emplace_back(&instance, std::move(&call<C, func>));
}
template<typename C, Ret(C::*func)(ArgType)>
void disconnect(C& instance)
{
Connection conn{&instance, &call<C, func>};
connections_.erase(std::remove(connections_.begin(), connections_.end(), conn), connections_.end());
}
};
//Test code
int main()
{
{
Window window{5};
Signal<void(KeyPressedEvent&)> signal;
signal.connect<&Window::kpEventHandler>(window); //Error C2974 'Signal<void (KeyPressedEvent &)>::connect': invalid template argument for 'C', type expected
signal.disconnect<&Window::kpEventHandler>(window); //Error C2974 'Signal<void (KeyPressedEvent &)>::disconnect': invalid template argument for 'C', type expected
}
std::cin.get();
return 0;
}
When I change the test code to the following, it obviously works.
signal.connect<Window, &Window::kpEventHandler>(window);
signal.disconnect<Window, &Window::kpEventHandler>(window);
I got it to work when I change Signal::connect() and Signal::disconnect() to the following implementation using an auto template parameter for the function pointer.
template<auto func, typename C>
void connect(C& instance)
{
static_assert(std::is_member_function_pointer<decltype(func)>::value,
"Signal::connect: func is not a pointer to a member function");
connections_.emplace_back(&instance, std::move(&call<C, func>));
}
template<auto func, typename C>
void disconnect(C& instance)
{
static_assert(std::is_member_function_pointer<decltype(func)>::value,
"Signal::disconnect: func is not a pointer to a member function");
Connection conn{&instance, &call<C, func>};
connections_.erase(std::remove(connections_.begin(), connections_.end(), conn), connections_.end());
}
signal.connect<&Window::kpEventHandler>(window); //works fine
signal.disconnect<&Window::kpEventHandler>(window); //works fine
When I change the order of the template parameters in this solution, I get an error as well:
template<typename C, auto func>
void disconnect(C& instance)
{
static_assert(std::is_member_function_pointer<decltype(func)>::value,
"Signal::disconnect: func is not a pointer to a member function");
Connection conn{&instance, &call<C, func>};
connections_.erase(std::remove(connections_.begin(), connections_.end(), conn), connections_.end());
}
signal.disconnect<&Window::kpEventHandler>(window); //Error C2974 'Signal<void (KeyPressedEvent &)>::disconnect': invalid template argument for 'C', type expected
So my questions are:
Why can't the compiler deduce the types of the parameters in my original version?
Why does it work when I change the Signal::connect() and Signal::disconnect() implementation to use 'auto func'?
Why do I get a compiler error when I change the order of the template parameters in the 'auto func' solution?
Thank you for helping me!
All your questions have the same answer: the order of template parameter is important and, to explicate a template parameter, you have to explicate all template parameters before it.
When you write
template<typename C, Ret(C::* func)(ArgType)>
void connect(C& instance)
or
template<typename C, auto func>
void disconnect(C& instance)
the first template parameter can be deduced from instance, the second one can't be deduced so has to be explicated.
But, this is the problem, if you have to explicate a template parameter, you must explicate all template parameter before it.
So
signal.connect<&Window::kpEventHandler>(window);
doesn't works because <&Window::kpEventHandler> explicate the first template parameter, that is C; and a &Window::kpEventHandler (that is a value) doesn't matches C, the first template argument (that has to be a type).
You have to explicate both template parameters, in the correct order, so
signal.connect<Window, &Window::kpEventHandler>(window);
signal.disconnect<Window, &Window::kpEventHandler>(window);
Different if you place the non-deducible template parameter in first position
template<auto func, typename C>
void connect(C& instance)
This way you can explicate the first template parameter (the func value) and let the compiler to deduce C from the argument instance.
So you can write
signal.connect<&Window::kpEventHandler>(window);
signal.disconnect<&Window::kpEventHandler>(window);
but works also if you explicate the second template parameter too
signal.connect<&Window::kpEventHandler, Windows>(window);
signal.disconnect<&Window::kpEventHandler, Windows>(window);

Passing a templated functor as an argument to a templated function in C++

I am trying to pass a templated functor into a templated function.
The code looks something like this:
template<typename T>
T func_1(T &a) {
return a;
}
template <typename T>
T test(T &a, std::function<T(T&)> &func){
return func(a);
}
int main(){
int a = 5;
std::cout << test(a, func_1) << std::endl;
}
However, I get the following compile error:
invalid initialization of non-const reference of type ‘std::function<int(int&)>&’ from an rvalue of type ‘’
The code works if I remove the template. Can someone help me understand why?
func_1 is function template. You have to pass a concrete type you want this function to be instantiated. In your case it is int, type of a variable.
std::cout << test(a, func_1<decltype(a)>) << std::endl;
Then, function object can be created taking func_1<int> instantiation. This function is temporary, but temporary cannot be bound to Lvalue reference, so signature of test should be modified to accept const Lvalue ref:
template <typename T>
T test(T &a, const std::function<T(T&)> &func){
// <---- const
return func(a);
}
The issue is that func_1 is just a template, to get a function pointer you first need a function (ie an instantiation of the function template).
You can get what you want by making func_1 an actual functor (ie callable object) that is not a template itself:
#include <functional>
#include <iostream>
struct func_1 {
template <typename T>
T operator()(T& a){ return a; }
};
template <typename T,typename F>
T test(T &a, F func){
return func(a);
}
int main(){
int a = 5;
std::cout << test(a, func_1{}) << std::endl;
// ^^ create instance
}
The "trick" is that only func_1::operator() is a template, so you can create objects of func_1 and pass them around before you know what T actually is. The operator is only instantiated when it is called in test but not in main.

Storing member function pointer from arbitrary class as class instance variable

There are a few questions on SO that address passing function pointers as parameters/arguments (here, here, here, etc.). In fact, I asked a related question the other day. However, this question is a little different.
My problem is that I am writing a class that I want to be extremely flexible.
What I have now works for non-member functions. It is posted below
template <typename T>
class MyClass
{
private:
typedef double (*firstFunctionPtr) (const T &var);
typedef bool (*secondFunctionPtr)(const T &var);
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc,
secondFunctionPtr secondFunc);
};
template<typename T>
MyClass<T>::MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc),
{}
However, this falls apart when I need to initialize with a pointer to a member function of some other, arbitrary, class, which, unfortunately for me, happens to be a common use case for my purposes.
This answer suggests that
In a proper C++ interface you might want to have a look at having your function take templated argument for function objects to use arbitrary class types.
However, I have not been able to make this compile. I've tried templating my typedefs (using the C++11 aliasing approach), and I've tried adding a second template parameter to the class to handle the calling class of those member functions, but neither approach has worked.
This Q/A seems to be getting towards what I'm trying to do, but I can't make heads or tails of it.
Can someone please explain how I might modify my class to handle arbitrary member functions pointers being passed in?
Furthermore, is it possible to make it so that it can handle either arbitrary member functions or non-member functions?
Lastly, is it possible to do this with templates?
For the record, I'm trying to avoid using the functional header, but it may be a fool's errand not to use it.
If you want MyClass to be a template that can hold both free function
pointers of types:
double (*)(const T &var);
bool (*)(const T &var);
for some parameter type T, or alternatively member-function
pointers of types:
double (C::*)(const T &var);
bool (C::*)(const T &var);
for some parameter types C and T then, MyClass must be parameterized
by both T and C and you require two specializations:
Where C is some non-class type
Where C is any class type
In case (1), the non-class type C cannot possibly have member functions,
so that one will implement the free-function pointer specialization.
In case (2), the class C could be one that has member functions, so that one
will implement the member-function pointer specialization.
The obvious choice for a non-class type C is void. So we can make C
default to void:
Primary template
template<typename T, typename C = void>
struct MyClass;
So that:
MyClass<T>
will be the free function pointer specialization for T, and:
MyClass<T,C>
for any C other than void, will be the member-function pointer specialization.
As you may know you can use std::enable_if
and SFINAE to make the compiler
chose one specialization of a class template or another, depending on whether one
of its template parameters U satisfies some compiletime test. You could take
that approach here, but another one is available that does not require that apparatus:
Starting with the primary template, we would just like to have:
Free function specialization
template<typename T>
struct MyClass<T>
{
... for free function pointers ...
};
and:
Member function specialization
template<typename T, typename C>
struct MyClass<T,C>
{
... for member function pointers ...
};
But we can't have just that, because the member function "specialization" has exactly
the same template parameters as the primary template. Which means it isn't
a specialization, and the compiler won't allow it.
You can easily remove that problem, however, simply by giving the primary
template one more defaulting template parameter that it doesn't need, but whose
presence allows both those specializations to stand.
New primary template
template <typename T, typename C = void, typename Default = void>
struct MyClass;
So here is an illustrative solution:
// Primary template
template <typename T, typename C = void, typename Default = void>
struct MyClass;
// Free function specialization
template <typename T>
struct MyClass<T>
{
using firstFunctor_t = double(*)(T const &);
using secondFunctor_t = bool(*)(T const &);
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(T const & var) {
return _firstFunc(var);
}
bool callSecond(T const & var) {
return _secondFunc(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
// Member function specialization
template <typename T, typename C>
struct MyClass<T,C>
{
using firstFunctor_t = double(C::*)(T const &);
using secondFunctor_t = bool(C::*)(T const &) const;
MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
: _firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
double callFirst(C & obj, T const & var) {
return (obj.*_firstFunc)(var);
}
double callFirst(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_firstFunc)(var);
}
bool callSecond(C & obj, T const & var) {
return (obj.*_secondFunc)(var);
}
bool callSecond(C const & obj, T const & var) {
auto & o = const_cast<C&>(obj);
return (o.*_secondFunc)(var);
}
private:
firstFunctor_t _firstFunc;
secondFunctor_t _secondFunc;
};
In the member function specialization, notice a couple of points that you might
not have considered:-
I decided that the second member function I want to store shall be a
const member function. It's more than likely that a member function of C
that take a T const & argument and returns bool will be a const member
function, isn't it? And if so, then that const-ness has to be part of
the member-function type definition that I use in the specialization:
using secondFunctor_t = bool(C::*)(T const &) const;
or attempts to instantiate the specialization with any bool (C::*)(T const &) const
will fail to compile.
Also, I have provided two overloads for each of MyClass<T,C>::callFirst
and MyClass<T,C>::callSecond, one with arguments:
C & obj, T const & var
and another with arguments:
C const & obj, T const & var
Without the second, attempts to call either MyClass<T,C>::callFirst
or MyClass<T,C>::callSecond with an obj that is const will fail to
compile.
For program to demo this solution you can append:
#include <iostream>
#include <string>
double foo(std::string const & s)
{
return std::stod(s);
}
bool bar(std::string const & s)
{
return s.size() > 0;
}
struct SomeClass
{
SomeClass(){};
double foo(std::string const & s) {
return ::foo(s);
}
bool bar(std::string const & s) const {
return ::bar(s);
}
};
int main()
{
MyClass<std::string> my0{foo,bar};
std::cout << std::boolalpha;
std::cout << my0.callFirst("1.11") << std::endl;
std::cout << my0.callSecond("Hello World") << std::endl;
MyClass<std::string,SomeClass> my1{&SomeClass::foo,&SomeClass::bar};
SomeClass thing;
std::cout << my1.callFirst(thing,"2.22") << std::endl;
std::cout << my1.callSecond(thing,"Hello World") << std::endl;
SomeClass const constThing;
std::cout << my1.callFirst(constThing,"3.33") << std::endl;
std::cout << my1.callSecond(constThing,"Hello World") << std::endl;
return 0;
}
See it live
You said that you want this template to be "extremely flexible". The
illustrated solution is fitted to your example, but you might be
interested in know that it isn't nearly as flexible as you could get.
For both free functions and member functions, with additional variadic template
parameters, your template could store and call [member] functions with
arbitary return types and arbitary numbers of arguments of arbitrary types.
See this question and
answer.
I will sugest to create a helper object which will store the type you want to work with:
template <typename RETURN, typename TYPE, typename CLASS>
struct function_pointer
{ using type_t = RETURN (CLASS::*)(const TYPE &); };
template <typename RETURN, typename TYPE>
struct function_pointer<RETURN, TYPE, std::nullptr_t>
{ using type_t = RETURN (*)(const TYPE &); };
This type will create a member-function-pointer if a class is provided as third parameter and a function-pointer otherwise. Now, we can use this helper in MyClass:
template <typename T, typename CLASS = std::nullptr_t>
class MyClass
{
using firstFunctionPtr = typename function_pointer<double, T, CLASS>::type_t;
using secondFunctionPtr = typename function_pointer<bool, T, CLASS>::type_t;
// Function pointers as member variables
firstFunctionPtr _firstFunc;
secondFunctionPtr _secondFunc;
public:
inline MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
_firstFunc(firstFunc),
_secondFunc(secondFunc)
{}
void call_first(CLASS &c, const T&v) { (c.*_firstFunc)(v); }
void call_second(CLASS &c, const T&v) { (c.*_secondFunc)(v); }
void call_first(const T&v) { (_firstFunc)(v); }
void call_second(const T&v) { (_secondFunc)(v); }
};
I've added call_* functions just to show a use case, which will be as below:
// Some class with the expected function signatures
struct S1
{
int i = 0;
double d(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Another class with the expected function signatures
struct S2
{
double d(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
bool b(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
};
// Free function with which could have the expected function signature
template <typename R>
R f(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
Using MyClass with an arbitrary class (S1):
S1 a{1}, b{2};
S2 c, d;
MyClass<int, S1> MCiS1(&S1::d, &S1::b);
MCiS1.call_first(a, 111); // Prints -> 1 double S1::d(const int&)
MCiS1.call_second(b, 222); // Prints -> 2 bool S1::b(const int&)
MCiS1.call_first(c, 111); // Error decltype(c) is not S1.
MCiS1.call_second(d, 222); // Error decltype(d) is not S1.
Using MyClass with a different class (S2):
MyClass<int, S2> MCiS2(&S2::d, &S2::b);
MCiS2.call_first(c, 111); // Prints -> double S2::d(const int&)
MCiS2.call_second(d, 222); // Prints -> bool S2::b(const int&)
MCiS2.call_first(a, 111); // Error decltype(c) is not S2.
MCiS2.call_second(b, 222); // Error decltype(d) is not S2.
Using MyClass with non-member functions:
MyClass<int> MCi(f<double>, f<bool>);
MCi.call_first(111); // Prints -> R f(const int&) [with R = double]
MCi.call_second(222); // Prints -> R f(const int&) [with R = bool]
Check the live demo Here.
All you need to do is bind the object instance for the member function pointer as a first argument.
struct foo {
float bar1(const type &var);
bool bar2(const type &var);
};
foo my_foo;
auto f1 = std::bind(&foo::bar1, my_foo, _1);
auto f2 = std::bind(&foo::bar2, my_foo, _1);
MyClass<type> my_obj(f1, f2);

How to make a function template that takes a functor with variable arguments

I'm trying to implement a function template (in C++11) whose parameter is a lambda with arbitrary parameters, and return a compatible std::function object. The goal is for the returned function when called to invoke the original lambda asynchronously, but for now I'm just returning the original lambda.
The problem is simply getting the compiler to accept a lambda as the parameter of the function template. Here are some simple templates:
#include <functional>
using namespace std;
template <class Arg>
function<void(Arg)> pass1(function<void(Arg)> fn) {
return fn;
}
template <class... Args>
function<void(Args...)> passn(function<void(Args...)> fn) {
return fn;
}
They do the same thing, it's just that pass1 only works on single-parameter functors while passn takes an arbitrary number.
So now we try using them, first pass1:
auto p1 = pass1( [](int a)->void {cout << a;} ); // ERROR
This doesn't work; the compiler can't seem to tell what parameters the lambda takes. Clang error message is:
Untitled.cpp:17:12: error: no matching function for call to 'pass1'
auto p1 = pass1( [](int a)->void {cout << a;} );
^~~~~
Untitled.cpp:6:21: note: candidate template ignored: could not match 'function<void (type-parameter-0-0)>' against '(lambda at Untitled.cpp:17:19)'
function<void(Arg)> pass1(function<void(Arg)> fn) {
I can work around this by explicitly specifying the template parameter type:
auto p2 = pass1<int>( [](int a)->void {cout << a;} ); // OK
However, this workaround fails with passn:
auto p3 = passn<int>( [](int a)->void {cout << a;} );
Untitled.cpp:23:12: error: no matching function for call to 'passn'
auto p3 = passn<int>( [](int a)->void {cout << a;} );
^~~~~~~~~~
Untitled.cpp:11:25: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against '(lambda at Untitled.cpp:23:24)'
function<void(Args...)> passn(function<void(Args...)> fn) {
^
The weird thing is that I can invoke passn if I pass it a function object:
function<void(int)> fn = [](int a)->void {cout << a;};
auto x = passn<int>(fn); // OK
...in fact, I don't even have to specify the template parameter type:
auto y = passn(fn); // OK
The function I actually need is going to be like passn, but I don't want the extra verbiage of having to wrap a function object around the lambda every time I call it. Am I missing something, or is this just not possible? Would it be possible in C++14?
You can use this implementation of passn:
#include <functional>
#include <iostream>
template <class RetVal, class T, class... Args>
std::function<RetVal(Args...)> get_fun_type(RetVal (T::*)(Args...) const);
template <class RetVal, class T, class... Args>
std::function<RetVal(Args...)> get_fun_type(RetVal (T::*)(Args...));
template <class T>
auto passn(T t) -> decltype(get_fun_type(&T::operator())) {
return t;
}
int main() {
auto fun = passn([](int a) { std::cout << a; });
fun(42);
}
(demo)
It assumes you pass in a type that has an operator(). It takes the address of that function and deduces parameters from that member pointer.
The function will fail if you pass it an object that has multiple operator()s because then taking its address will be ambiguous, but lambdas will not produce that problem.

Disambiguate overloaded member function pointer being passed as template parameter

I am attempting to recreate the Observer pattern where I can perfectly forward parameters to a given member function of the observers.
If I attempt to pass the address of a member function which has multiple overrides, it cannot deduce the correct member function based on the arguments.
#include <iostream>
#include <vector>
#include <algorithm>
template<typename Class>
struct observer_list
{
template<typename Ret, typename... Args, typename... UArgs>
void call(Ret (Class::*func)(Args...), UArgs&&... args)
{
for (auto obj : _observers)
{
(obj->*func)(std::forward<UArgs>(args)...);
}
}
std::vector<Class*> _observers;
};
struct foo
{
void func(const std::string& s)
{
std::cout << this << ": " << s << std::endl;
}
void func(const double d)
{
std::cout << this << ": " << d << std::endl;
}
};
int main()
{
observer_list<foo> l;
foo f1, f2;
l._observers = { &f1, &f2 };
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
return 0;
}
This fails to compile with template argument deduction/substitution failed.
Note that I had Args... and UArgs... because I need to be able to pass parameters which are not necessarily the same type asthe type of the function signature, but are convertible to said type.
I was thinking I could use a std::enable_if<std::is_convertible<Args, UArgs>> call to disambiguate, but I don't believe I can do this with a variadic template parameter pack?
How can I get the template argument deduction to work here?
The issue is here:
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
For both lines, the compiler doesn't know which foo::func you are referring to. Hence, you have to disambiguate yourself by providing the type information that is missing (i.e., the type of foo:func) through casts:
l.call(static_cast<void (foo::*)(const std::string&)>(&foo::func), "hello");
l.call(static_cast<void (foo::*)(const double )>(&foo::func), 0.5);
Alternatively, you can provide the template arguments that the compiler cannot deduce and that define the type of func:
l.call<void, const std::string&>(&foo::func, "hello");
l.call<void, double >(&foo::func, 0.5);
Notice that you have to use double and not const double above. The reason is that generally double and const double are two different types. However, there's one situation where double and const double are considered as if they were the same type: as function arguments. For instance,
void bar(const double);
void bar(double);
are not two different overloads but are actually the same function.