Basically, what I want to be able to do is take a lambda with any number of any type of parameters and convert it to an std::function.
I've tried the following and neither method works.
std::function([](){});//Complains that std::function is missing template parameters
template <typename T> void foo(function<T> f){}
foo([](){});//Complains that it cannot find a matching candidate
The following code does work however, but it is not what I want because it requires explicitly stating the template parameters which does not work for generic code.
std::function<void()>([](){});
I've been mucking around with functions and templates all evening and I just can't figure this out, so any help would be much appreciated.
As mentioned in a comment, the reason I'm trying to do this is because I'm trying to implement currying in C++ using variadic templates. Unfortunately, this fails horribly when using lambdas. For example, I can pass a standard function using a function pointer.
template <typename R, typename...A>
void foo(R (*f)(A...)) {}
void bar() {}
int main() {
foo(bar);
}
However, I can't figure out how to pass a lambda to such a variadic function. Why I'm interested in converting a generic lambda into an std::function is because I can do the following, but it ends up requiring that I explicitly state the template parameters to std::function which is what I am trying to avoid.
template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
foo(std::function<void()>([](){}));
}
You can't pass a lambda function object as an argument of type std::function<T> without explicitly specifying the template argument T. Template type deduction tries to match the type of your lambda function to the std::function<T> which it just can't do in this case - these types are not the same. Template type deduction doesn't consider conversions between types.
It is possible if you can give it some other way to deduce the type. You can do this by wrapping the function argument in an identity type so that it doesn't fail on trying to match the lambda to std::function (because dependent types are just ignored by type deduction) and giving some other arguments.
template <typename T>
struct identity
{
typedef T type;
};
template <typename... T>
void func(typename identity<std::function<void(T...)>>::type f, T... values) {
f(values...);
}
int main() {
func([](int x, int y, int z) { std::cout << (x*y*z) << std::endl; }, 3, 6, 8);
return 0;
}
This is obviously not useful in your situation though because you don't want to pass the values until later.
Since you don't want to specify the template parameters, nor do you want to pass other arguments from which the template parameters can be deduced, the compiler won't be able to deduce the type of your std::function argument.
TL;DR: What you ask can be done using CTAD, a feature that enables you to create an std::function of the expected type, right at the call site without spelling out the template arguments:
foo(std::function([](int arg){ return Bar{}; }));
// ^^^^^^^^^^^^^ constructor call w/o templates
// std::function<Bar(int)> will be auto-deduced
Demo
If you are interested on how to emulate the mechanics of such a deduction, or need to work with a pre c++17 compiler, check the rest of the answer.
You can use a dedicated/retrospective cast. Once you have a tool like this
#include <functional>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
return func;
}
you can say FFL() to all lambda types to have them converted to what would be the correct version of std::function
template <typename... Args> void Callback(std::function<void(Args...)> f){
// store f and call later
}
int main()
{
Callback(FFL([](int a, float b){
// do something
}));
return 0;
}
Display
As shown at Inferring the call signature of a lambda or arbitrary callable for "make_function", you can infer the calling signature of a lambda (or any other functor with a single calling signature) from its (single) operator():
template<typename T> struct remove_class { };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); };
template<typename T>
struct get_signature_impl { using type = typename remove_class<
decltype(&std::remove_reference<T>::type::operator())>::type; };
template<typename R, typename... A>
struct get_signature_impl<R(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(&)(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(*)(A...)> { using type = R(A...); };
template<typename T> using get_signature = typename get_signature_impl<T>::type;
This is a rather inflexible approach, though; as R. Martinho Fernandes says, it won't work for functors with multiple operator()s, nor for functors with templated operator() or for (C++14) polymorphic lambdas. This is why bind defers inference of its result type until the eventual call attempt.
It is possible to get the needed std::function type for lambda using derivation, decltype, variadic templates and a few type traits:
namespace ambient {
template <typename Function>
struct function_traits : public function_traits<decltype(&Function::operator())> {};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
typedef ReturnType (*pointer)(Args...);
typedef const std::function<ReturnType(Args...)> function;
};
template <typename Function>
typename function_traits<Function>::function to_function (Function& lambda) {
return static_cast<typename function_traits<Function>::function>(lambda);
}
template <class L>
struct overload_lambda : L {
overload_lambda(L l) : L(l) {}
template <typename... T>
void operator()(T&& ... values){
// here you can access the target std::function with
to_function(*(L*)this)(std::forward<T>(values)...);
}
};
template <class L>
overload_lambda<L> lambda(L l){
return overload_lambda<L>(l);
}
}
I use it in my code like this:
ambient::lambda([&](const vector<int>& val){
// some code here //
})(a);
PS: in my real case I then save this std::function object and its arguments inside a generic kernel objects that I can execute later on demand via virtual functions.
Isn't currying already implemented with std::bind?
auto sum = [](int a, int b){ return a+b; };
auto inc = std::bind( sum, _1, 1 );
assert( inc(1)==2 );
This could be interesting for you: https://gist.github.com/Manu343726/94769034179e2c846acc
That is an experiment I have written a month ago. The goal was to create a functor-like C++ template which emulates Haskell's partial calls closures, i.e. the automatic creation of a closure of m-n argumments when you call with n argumments a function with m parameters.
This is one example of what this experiment is cappable to do:
int f( int a, int b, int c, int d)
{
return a+b+c+d;
}
int main()
{
auto foo = haskell::make_function( f );
auto a = foo , 1 , 2 , 3; //a is a closure function object with one parameter
std::cout << a , 4 << std::endl; //Prints 10
}
haskell::make_function uses some type traits to take care of the different types of function entities, lambdas included:
auto f = haskell::make_function( []( int x, int y , int z ){ return x*y*z; } );
auto a = f(1,2); //a is functor with one parameter (Using the alternative C++-like syntax)
auto b = a(3); // b is 6
As you can see, I use comma operator to mmimic Haskell syntax, but you could change it to the call operator to achieve your goal syntax.
Your are completely free to do anything you want with the code (Check the license).
In C++17 there is the constructor type deduction. So you can save some typing for the std::function template arguments. This is not quite nothing, but a bit less.
template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
foo(std::function([](){}));
}
Seven years later and probably the simplest solution then, still works today.
template< char const * (*name) () >
struct user {
auto id() { return name(); }
} ;
Usage
constexpr auto lama () { return "Lama"; }
int main( int , char * [] )
{
auto amuser = user< lama >{} ;
cout << boolalpha << amuser.id() << endl ;
}
Lambda afficionados are served too
auto cat = [] () constexpr { return "Cat"; } ;
auto sneaky = user< cat >{} ;
cout << boolalpha << sneaky.id() << endl ;
With lambda expressions that have explicit template parameter lists (C++20 feature), you can write the function much easier as shown below:
template <typename F,typename... T>
auto func(F f, T... values) {
return f(values...);
}
int main() {
auto result = func([]<typename... T>(T...args){
return (...*args);
},1,2,3,6,22);
std::cout<<result<<"\n";
}
with std::result_of, if you use only function (no class/struct, 'cause the declaration would be nothing like the std::function, and it really ugly),you can now make it like:
template <typename Func, typename ...Args>
std::result_of_t<Func(Args...)> func(Func function, Args... args) {
/// now do your staff here
}
/// usage:
func([](){printf("lambda function\n"});
Related
I have a complex problem that can be boiled down to the following deduction guide
template <class R> R return_r() { return R{}; }
void accep_float(float arg) { (void)arg; }
int main() {
accep_float(return_r());
}
Can I put a deduction guide to make the template deduct the right type according to the accepting function, like float here accep_float(return_type<float>());?
A templated conversion operator can be used for this kind of "backward" deduction:
struct foo {
template <typename T>
operator T() { return T{};}
};
void accep_float(float arg) { (void)arg; }
int main() {
accep_float(foo{});
}
I am not aware of deduction guides for function templates. Anyhow, you must first call foo{} (or return_r in your case) and only then the conversion to some argument type of accep_float can be done.
This pure backwards deduction is not possible, as far as I know. However, you can figure out the parameter types of any function beforehand, and use that to pass it in manually:
namespace detail {
template<typename R, typename... A>
constexpr auto parameter_types(R(*)(A...)) {
return std::tuple<A...>{};
}
template<typename R, typename... A>
constexpr auto parameter_types(std::function<R(A...)>) {
return std::tuple<A...>{};
}
template<typename C, typename R, typename... A>
constexpr auto parameter_types(R(C::*)(A...)) {
return std::tuple<A...>{};
}
template<typename C, typename R, typename... A>
constexpr auto parameter_types(R(C::*)(A...) const) {
return std::tuple<A...>{};
}
}
template<typename F>
using parameter_types = decltype(detail::parameter_types(std::declval<F>()));
template<typename F>
using first_parameter = std::tuple_element_t<0u, parameter_types<F>>;
and now in main you can use first_parameter like this:
int main() {
using R = first_parameter<decltype(accep_float)>;
accep_float(return_r<R>());
}
with this method you can deduce and number of parameters, simple use std::tuple_element_t<N, parameter_types<F>>;
Now it would be neet to make some kind of apply_deduce function that will call the functions accordingly, however you can't just pass a template function name without naming it's template, therefore defeating the purpose.
Not exactly the most elegant, but since there is no other way, a macro will do the job:
#define apply_deduced(f1, f2) f1(f2<first_parameter<decltype(f1)>>())
int main() {
apply_deduced(accep_float, return_r);
}
Basically, what I want to be able to do is take a lambda with any number of any type of parameters and convert it to an std::function.
I've tried the following and neither method works.
std::function([](){});//Complains that std::function is missing template parameters
template <typename T> void foo(function<T> f){}
foo([](){});//Complains that it cannot find a matching candidate
The following code does work however, but it is not what I want because it requires explicitly stating the template parameters which does not work for generic code.
std::function<void()>([](){});
I've been mucking around with functions and templates all evening and I just can't figure this out, so any help would be much appreciated.
As mentioned in a comment, the reason I'm trying to do this is because I'm trying to implement currying in C++ using variadic templates. Unfortunately, this fails horribly when using lambdas. For example, I can pass a standard function using a function pointer.
template <typename R, typename...A>
void foo(R (*f)(A...)) {}
void bar() {}
int main() {
foo(bar);
}
However, I can't figure out how to pass a lambda to such a variadic function. Why I'm interested in converting a generic lambda into an std::function is because I can do the following, but it ends up requiring that I explicitly state the template parameters to std::function which is what I am trying to avoid.
template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
foo(std::function<void()>([](){}));
}
You can't pass a lambda function object as an argument of type std::function<T> without explicitly specifying the template argument T. Template type deduction tries to match the type of your lambda function to the std::function<T> which it just can't do in this case - these types are not the same. Template type deduction doesn't consider conversions between types.
It is possible if you can give it some other way to deduce the type. You can do this by wrapping the function argument in an identity type so that it doesn't fail on trying to match the lambda to std::function (because dependent types are just ignored by type deduction) and giving some other arguments.
template <typename T>
struct identity
{
typedef T type;
};
template <typename... T>
void func(typename identity<std::function<void(T...)>>::type f, T... values) {
f(values...);
}
int main() {
func([](int x, int y, int z) { std::cout << (x*y*z) << std::endl; }, 3, 6, 8);
return 0;
}
This is obviously not useful in your situation though because you don't want to pass the values until later.
Since you don't want to specify the template parameters, nor do you want to pass other arguments from which the template parameters can be deduced, the compiler won't be able to deduce the type of your std::function argument.
TL;DR: What you ask can be done using CTAD, a feature that enables you to create an std::function of the expected type, right at the call site without spelling out the template arguments:
foo(std::function([](int arg){ return Bar{}; }));
// ^^^^^^^^^^^^^ constructor call w/o templates
// std::function<Bar(int)> will be auto-deduced
Demo
If you are interested on how to emulate the mechanics of such a deduction, or need to work with a pre c++17 compiler, check the rest of the answer.
You can use a dedicated/retrospective cast. Once you have a tool like this
#include <functional>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
return func;
}
you can say FFL() to all lambda types to have them converted to what would be the correct version of std::function
template <typename... Args> void Callback(std::function<void(Args...)> f){
// store f and call later
}
int main()
{
Callback(FFL([](int a, float b){
// do something
}));
return 0;
}
Display
As shown at Inferring the call signature of a lambda or arbitrary callable for "make_function", you can infer the calling signature of a lambda (or any other functor with a single calling signature) from its (single) operator():
template<typename T> struct remove_class { };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); };
template<typename T>
struct get_signature_impl { using type = typename remove_class<
decltype(&std::remove_reference<T>::type::operator())>::type; };
template<typename R, typename... A>
struct get_signature_impl<R(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(&)(A...)> { using type = R(A...); };
template<typename R, typename... A>
struct get_signature_impl<R(*)(A...)> { using type = R(A...); };
template<typename T> using get_signature = typename get_signature_impl<T>::type;
This is a rather inflexible approach, though; as R. Martinho Fernandes says, it won't work for functors with multiple operator()s, nor for functors with templated operator() or for (C++14) polymorphic lambdas. This is why bind defers inference of its result type until the eventual call attempt.
It is possible to get the needed std::function type for lambda using derivation, decltype, variadic templates and a few type traits:
namespace ambient {
template <typename Function>
struct function_traits : public function_traits<decltype(&Function::operator())> {};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
typedef ReturnType (*pointer)(Args...);
typedef const std::function<ReturnType(Args...)> function;
};
template <typename Function>
typename function_traits<Function>::function to_function (Function& lambda) {
return static_cast<typename function_traits<Function>::function>(lambda);
}
template <class L>
struct overload_lambda : L {
overload_lambda(L l) : L(l) {}
template <typename... T>
void operator()(T&& ... values){
// here you can access the target std::function with
to_function(*(L*)this)(std::forward<T>(values)...);
}
};
template <class L>
overload_lambda<L> lambda(L l){
return overload_lambda<L>(l);
}
}
I use it in my code like this:
ambient::lambda([&](const vector<int>& val){
// some code here //
})(a);
PS: in my real case I then save this std::function object and its arguments inside a generic kernel objects that I can execute later on demand via virtual functions.
Isn't currying already implemented with std::bind?
auto sum = [](int a, int b){ return a+b; };
auto inc = std::bind( sum, _1, 1 );
assert( inc(1)==2 );
This could be interesting for you: https://gist.github.com/Manu343726/94769034179e2c846acc
That is an experiment I have written a month ago. The goal was to create a functor-like C++ template which emulates Haskell's partial calls closures, i.e. the automatic creation of a closure of m-n argumments when you call with n argumments a function with m parameters.
This is one example of what this experiment is cappable to do:
int f( int a, int b, int c, int d)
{
return a+b+c+d;
}
int main()
{
auto foo = haskell::make_function( f );
auto a = foo , 1 , 2 , 3; //a is a closure function object with one parameter
std::cout << a , 4 << std::endl; //Prints 10
}
haskell::make_function uses some type traits to take care of the different types of function entities, lambdas included:
auto f = haskell::make_function( []( int x, int y , int z ){ return x*y*z; } );
auto a = f(1,2); //a is functor with one parameter (Using the alternative C++-like syntax)
auto b = a(3); // b is 6
As you can see, I use comma operator to mmimic Haskell syntax, but you could change it to the call operator to achieve your goal syntax.
Your are completely free to do anything you want with the code (Check the license).
In C++17 there is the constructor type deduction. So you can save some typing for the std::function template arguments. This is not quite nothing, but a bit less.
template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
foo(std::function([](){}));
}
Seven years later and probably the simplest solution then, still works today.
template< char const * (*name) () >
struct user {
auto id() { return name(); }
} ;
Usage
constexpr auto lama () { return "Lama"; }
int main( int , char * [] )
{
auto amuser = user< lama >{} ;
cout << boolalpha << amuser.id() << endl ;
}
Lambda afficionados are served too
auto cat = [] () constexpr { return "Cat"; } ;
auto sneaky = user< cat >{} ;
cout << boolalpha << sneaky.id() << endl ;
With lambda expressions that have explicit template parameter lists (C++20 feature), you can write the function much easier as shown below:
template <typename F,typename... T>
auto func(F f, T... values) {
return f(values...);
}
int main() {
auto result = func([]<typename... T>(T...args){
return (...*args);
},1,2,3,6,22);
std::cout<<result<<"\n";
}
with std::result_of, if you use only function (no class/struct, 'cause the declaration would be nothing like the std::function, and it really ugly),you can now make it like:
template <typename Func, typename ...Args>
std::result_of_t<Func(Args...)> func(Func function, Args... args) {
/// now do your staff here
}
/// usage:
func([](){printf("lambda function\n"});
If I pass a lambda as a template parameter, what is the actual type of that parameter that is deduced? I have looked on the VS2017 debugger and the type of this lambda: [](int x) {return x; } is filename::__I2::int<lambda>(int).
The reason I am asking this is because I want to pass a lambda and then create an internal std::function from this. Note that this relates to this answer and why we have to use CTAD to construct an internal std::function instead of just passing the template parameter to a std::function.
As an example, I would like to do something like the following:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<Func> internalFunc = f; //this does not work
}
//usage
createStdFunc([](int x) {return x; }, 5);
However, this does not work, and I get the error 'initialising' cannot convert from 'Func' to 'std::function<Func>'. I am not sure how the types differ and how they have changed from passing into the function to initialising the std::function. Please note that I do know you can use CTAD from 2017 onwards, but was wondering what a solution for 2014 and before would have been?
In C++14 you can use return type deduction to figure out function signature, this implies that types of arguments passed into createStdFunc match:
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
std::function<std::result_of_t<Func(Args...)> (Args...)> internalFunc{f}; //this does work
}
My way
#include <iostream>
#include <functional>
template <typename R, typename T, typename ... As>
constexpr std::function<R(As...)> getFuncType (R(T::*)(As...) const);
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
decltype(getFuncType(&F::operator())) internalFunc { f };
internalFunc(as...);
}
int main ()
{
createStdFunc([](int x) { std::cout << x << std::endl; }, 5);
}
Maybe also through a using
template <typename F>
using funcType = decltype(getFuncType(&F::operator()));
template <typename F, typename ... As>
void createStdFunc (F const & f, As ... as)
{
funcType<F> internalFunc { f };
internalFunc(as...);
}
The problem inside your code is that Func is not a function type. It's the type of the lambda. Lambdas compile down to something like this:
// equivalent:
// auto my_lambda = [](int v){ return v; };
struct /* unnamed */ {
auto operator()(int v) const { return v; }
} my_lambda;
The solution would be to extract the type of the operator() from the closure type:
using my_lambda_t = decltype(my_lambda);
// type: int(my_lambda_t::*)(int) const;
auto call_operator = &decltype(my_lambda_t)::operator();
Then, from the type of the operator(), you can deduce the type of the arguments and the return type:
template<typename>
struct extract_types {};
template<typename R, typename C, typename... Args>
struct extract_types<R(C::*)(Args...) const> {
using result = R;
using args_types = std::tuple<Args...>;
};
Generalized versions of this pattern is shipped in Boost.CallableTraits
You can write a simple trait to generalize callable types. If you handle both function pointers and anything with operator() (both const and non-const) you should be able to cover most use cases.
#include <tuple>
// For callable types
template<class T>
struct func_type : func_type<decltype(&T::operator())>{};
// For callable types' member functions (including `operator()`)
template<class T, class R, class ... Args >
struct func_type<R (T::*)(Args...) const> : func_type<R(*)(Args...)> {};
// For function pointers
template<class R, class ... Args >
struct func_type<R (*)(Args...)> {
using type = R(Args...);
using result = R;
using args = std::tuple<Args...>;
};
template<class T>
using func_type_t = typename func_type<T>::type;
func_type_t<T> should then give you a function type for most callable types T. Example uses :
#include <functional>
template<class Func, class... Args>
void createStdFunc(Func f, Args... args) {
// Replaced `Func` with `func_type_t<Func>`
std::function<func_type_t<Func>> internalFunc = f;
}
int foo(int x) { return x; }
struct bar {
int operator()(int x) { return x; };
};
int main()
{
// With lambda expression
createStdFunc([](int x) {return x; }, 5);
// With function pointer
createStdFunc(foo, 5);
// With std::function
std::function<int(int)> std_func = [](int x) {return x; };
createStdFunc(std_func, 5);
// With a functor
createStdFunc(bar{}, 5);
}
The std::function template expects as its argument a function type from which it infers the return and parameter type for the callable to wrap. The closure type of a lambda expression is a callable, but it's not a function type.
C++17 introduced deduction guides for std::function which allow the correct type to be deduced from any callable argument. Pre C++17, you could use a set of helper templates to deduce the correct type, for example:
template <typename F>
struct deduce_func_type_helper;
template <typename R, typename... Args>
struct deduce_func_type_helper<R(&)(Args...)>
{
using type = std::function<R(Args...)>;
};
template <typename R, typename... Args>
struct deduce_func_type_helper<R(*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...)> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) const> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename C, typename R, typename... Args>
struct deduce_func_type_helper<R(C::*)(Args...) volatile> : deduce_func_type_helper<R(&)(Args...)> {};
template <typename F>
struct deduce_func_type_helper<F&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper<F&&> : deduce_func_type_helper<std::remove_cv_t<F>> {};
template <typename F>
struct deduce_func_type_helper : deduce_func_type_helper<decltype(&F::operator())> {};
template <typename F>
using func_type_t = typename deduce_func_type_helper<F>::type;
live example here
Note that above example is not complete; it's missing some specializations, e.g., for all possible combinations of const, volatile, and different ref qualifiers. So this can get quite verbose, you will probably want to go with C++17 if you can…
We have polymorphic classes A and B like:
struct A {
virtual ~A() {}
};
struct B final : public A {
void f() { std::cout << "f" << std::endl; }
};
I want to assign a variable with std::function<void(A*)> from the lambda function with the type of void(B*) without explicitly applying dynamic_cast for the arguments as
std::function<void(A*)> funcA = [](A* a) {
[](B* b) { b->f(); }(dynamic_cast<B*>(a));
};
B b;
funcA(&b);
Are there any ways to automatically achieve this without wrapping the internal function with [](A* a){}?
I set off with the goal of making the following syntax work:
std::function<void(A*)> funcA = dynStdFunc([](B* b) { b->f(); });
To this end, dynStdFunc must:
Detect the parameters of the provided lambda;
Detect the parameters of funcA;
This isn't actually needed on our side, see the update at the end.
Generate a new functor, which glues both parameter lists together via dynamic_cast.
1. Detecting parameters has alrady been the subject of another answer of mine. We can use the following type trait:
// C++17's void_t
template <class...>
using void_t = void;
// Pack of arbitrary types
template <class...>
struct pack { };
namespace detail_parameters {
template <class F, class = void_t<>>
struct parameters { };
template <class F>
struct parameters<F, void_t<decltype(&F::operator ())>>
: parameters<decltype(&F::operator ())> { };
template <class R, class... Params>
struct parameters<R(Params...)> { using type = pack<Params...>; };
// More specializations for functions, function pointers,
// member function pointers...
}
// Retrieve the parameter list from a functionoid
template <class F>
using parameters = typename detail_parameters::parameters<std::remove_reference_t<F>>::type;
This takes in a functionoid type, and returns a pack<T...> containing its parameter types. Great.
2. the parameters required by the std::function aren't known from inside dynStdFunc. The way we make this work is by returning a temporary object, which contains a template for a conversion operator to std::function<Ret(Args...)>.
namespace detail_dynStdFunc {
// F = functionoid, Ps = pack of its parameters
template <class F, class Ps>
struct wrapper;
template <class F, class... Ps>
struct wrapper<F, pack<Ps...>> {
template <class Ret, class... Args>
operator std::function<Ret(Args...)> () {
// Now we know what parameters the `std::function` needs
}
F f;
};
}
template <class F>
auto dynStdFunc(F &&f) {
return detail_dynStdFunc::wrapper<
std::remove_reference_t<F>,
parameters<F>
>{std::forward<F>(f)};
}
3. We've got all we need, generating the new functor is straightforward:
template <class Ret, class... Args>
operator std::function<Ret(Args...)> () {
return [f_ = std::move(f)](Args... args) -> Ret {
return f_(dynamic_cast<Ps>(args)...);
};
}
And that's it! You can see it working live on Coliru.
Update: turns out I've done twice the work I needed to, because std::function can actually instantiate and wrap generic functors directly. Thanks Yakk!
So performing the conversion ourselves is pointless -- let's drop the wrapper:
template <class F, class... Ps>
auto dynStdFunc(F &&f, pack<Ps...>) {
return [f_ = std::forward<F>(f)](auto *... args) -> decltype(auto) {
return f_(dynamic_cast<Ps>(args)...);
};
}
template <class F>
auto dynStdFunc(F &&f) {
return dynStdFunc(std::forward<F>(f), parameters<F>{});
}
See it live on Coliru.
How does one take a templated pointer to a member function?
By templated I mean that the following types are not known in advance:
template param T is class of the pointer to member
template param R is the return type
variadic template param Args... are the parameters
Non-working code to illustrate the issue:
template <???>
void pmf_tparam() {}
// this works, but it's a function parameter, not a template parameter
template <class T, typename R, typename... Args>
void pmf_param(R (T::*pmf)(Args...)) {}
struct A {
void f(int) {}
};
int main() {
pmf_tparam<&A::f>(); // What I'm looking for
pmf_param(&A::f); // This works but that's not what I'm looking for
return 0;
}
Is it possible to achieve the desired behavior in C++11?
I don't think this notation is possible, yet. There is proposal P0127R1 to make this notation possible. The template would be declared something like this:
template <auto P> void pmf_tparam();
// ...
pmf_tparam<&S::member>();
pmf_tparam<&f>();
The proposal to add auto for non-type type parameters was voted into the C++ working paper in Oulu and the result was voted to become the CD leading towards C++17 also in Oulu. Without the auto type for the non-type parameter, you'd need to provide the type of the pointer:
template <typename T, T P> void pmf_tparam();
// ...
pmf_tparam<decltype(&S::member), &S::member>();
pmf_tparam<decltype(&f), &f>();
As you've not said really what you are after in the function, the simplest is:
struct A {
void bar() {
}
};
template <typename T>
void foo() {
// Here T is void (A::*)()
}
int main(void) {
foo<decltype(&A::bar)>();
}
However if you want the signature broken down, I'm not sure there is a way to resolve the types directly, however you can with a little indirection...
struct A {
void bar() {
std::cout << "Call A" << std::endl;
}
};
template <typename R, typename C, typename... Args>
struct composer {
using return_type = R;
using class_type = C;
using args_seq = std::tuple<Args...>;
using pf = R (C::*)(Args...);
};
template <typename C, typename C::pf M>
struct foo {
static_assert(std::is_same<C, composer<void, A>>::value, "not fp");
typename C::return_type call(typename C::class_type& inst) {
return (inst.*M)();
}
template <typename... Args>
typename C::return_type call(typename C::class_type& inst, Args&&... args) {
return (inst.*M)(std::forward<Args...>(args...));
}
};
template <class T, typename R, typename... Args>
constexpr auto compute(R (T::*pmf)(Args...)) {
return composer<R, T, Args...>{};
}
int main() {
foo<decltype(compute(&A::bar)), &A::bar> f;
A a;
f.call(a);
}
The above should do what you are after...
What you can do is
template <template T, T value>
void pmf_tparam() {}
and then
pmf_tparam<decltype(&A::f), &A::f>();
The problem is not knowing the type of the argument and wanting a template argument of that type.
With an additional decltype (still in the templated parameter), this works:
#include <iostream>
using namespace std;
template <typename T, T ptr>
void foo (){
ptr();
}
void noop() {
cout << "Hello" << endl;
}
int main() {
//Here have to use decltype first
foo<decltype(&noop), noop>();
return 0;
}