Initialize class containing a std::function with a lambda - c++

I created a template class containing a std::function as a member the following way:
template<typename Ret, typename... Args>
class Foo
{
private:
std::function<Ret(Args...)> _func;
public:
Foo(const std::function<Ret(Args...)>& func):
_func(func)
{}
};
In order not to have to specify the arguments and return type of the passed function, I created some make_foo overloads:
template<typename Ret, typename... Args>
auto make_foo(Ret (&func)(Args...))
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
template<typename Ret, typename... Args>
auto make_foo(const std::function<Ret(Args...)>& func)
-> Foo<Ret, Args...>
{
return { func };
}
However, I was unable to create a make_foo overload that takes a lambda as parameter:
template<typename Ret, typename... Args>
auto make_foo(??? func)
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
I just can't find a way to have the return type and argument types automatically deduced from the lambda. Is there an idiomatic way to solve such a problem?

Ok, so I thought I would die, but I finally managed to do it ç_ç
First, I used the usual indices. Since I do not have the official ones, I used old indices I wrote some months ago:
template<std::size_t...>
struct indices {};
template<std::size_t N, std::size_t... Ind>
struct make_indices:
make_indices<N-1, N-1, Ind...>
{};
template<std::size_t... Ind>
struct make_indices<0, Ind...>:
indices<Ind...>
{};
Then, I used some function traits found somewhere on StackOverflow. They are nice, and I think that they are equivalent to the Boost library linked in the comments:
template<typename T>
struct function_traits:
function_traits<decltype(&T::operator())>
{};
template<typename C, typename Ret, typename... Args>
struct function_traits<Ret(C::*)(Args...) const>
{
enum { arity = sizeof...(Args) };
using result_type = Ret;
template<std::size_t N>
using arg = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
Then, I was able to write a proper make_foo function and it implementation function, since both are required to use indices. Be careful, it's plain ugly:
template<typename Function, std::size_t... Ind>
auto make_foo_(Function&& func, indices<Ind...>)
-> Foo<
typename function_traits<typename std::remove_reference<Function>::type>::result_type,
typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...>
{
using Ret = typename function_traits<typename std::remove_reference<Function>::type>::result_type;
return { std::function<Ret(typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...)>(func) };
}
template<typename Function, typename Indices=make_indices<function_traits<typename std::remove_reference<Function>::type>::arity>>
auto make_foo(Function&& func)
-> decltype(make_foo_(std::forward<Function>(func), Indices()))
{
return make_foo_(std::forward<Function>(func), Indices());
}
The code is somehow ugly and unreadable, but it definitely works. Hope it does not rely on some implementation-defined behaviour now. Also, thanks all for your advice, it helped! :)
int main()
{
auto lambda = [](int i, float b, long c)
{
return long(i*10+b+c);
};
auto foo = make_foo(lambda);
std::cout << foo(5, 5.0, 2) << std::endl; // 57, it works!
}
And here is the live example :)

I have an example that works with mutable lambdas. I can't quite figure out how to get the CV member qualification right.
First, here's the function template we're after:
#include <functional>
template <typename R, typename ...Args>
void foo(std::function<R(Args...)> f)
{ }
Now we'll let a function template bar take an arbitrary lambda and call the right version of foo, by inspecting the type of the lambda's operator():
#include <type_traits>
template <typename> struct remove_member;
template <typename C, typename T>
struct remove_member<T C::*>
{ using type = T; };
template <typename F>
void bar(F f)
{
using ft = decltype(&F::operator());
foo(std::function<typename remove_member<ft>::type>(f));
}
Example:
int q;
bar([&](int a, int b) mutable -> int { q = a + b; return q / b; });
You can use normal, const lambdas with this modified trait, though I don't like having to spell the function type out:
template <typename C, typename R, typename ...Args>
struct remove_member<R (C::*)(Args...) const>
{ using type = R(Args...); };
I thought it might work with the original code if I use typename std::remove_cv<T>::type, but at least on GCC this doesn't work because of some strange __attribute__((const)) that's set on the lambda's operator type which seems to interfere with the template specialization.

Related

Passing lambdas as template parameters: what type is actually deduced?

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…

get unique return type of template function/generic lambda

Is there a way to obtain the return type of a template function/generic lambda without having to specify the argument types?
template<class F>
struct unique_result_of {
using type = std::result_of_t<F( *any valid parameter combination that F can be called upon* )>;
}
auto f = [](auto x, auto y, int z) -> int {};
auto g = [](double x, auto y) -> float {};
using return_type_f = typename unique_result_of<decltype(f)>::type; // should be int
using return_type_g = typename unique_result_of<decltype(g)>::type; // should be float
Of couse this should only work if all functions generated by the same template function name do have a unique return type.
Your given example will work with the following, but there are some caveats, mentioned below
#include<type_traits>
#include<utility>
struct ubiq
{
template<typename T>
constexpr operator T&() const;
};
template<size_t>
ubiq make_ubiq();
struct broken_t;
template<typename T>
static constexpr bool is_broken_v = std::is_same_v<T, broken_t>;
template<typename T, size_t I0, size_t... I>
auto call(std::index_sequence<I0, I...>)
-> decltype(std::declval<T>()(make_ubiq<I0>(), make_ubiq<I>()...));
template<typename T>
auto call(std::index_sequence<>) -> decltype(std::declval<T>()());
template<typename T, size_t... I>
auto call(std::index_sequence<I...>) -> broken_t;
template<typename T, size_t N>
using call_t = decltype(call<T>(std::make_index_sequence<N>{}));
template<typename Void, typename...>
struct collapse
{
using type = broken_t;
};
template<typename T>
struct collapse<std::enable_if_t<!is_broken_v<T>>, T>
{
using type = T;
};
template<typename T, typename... Ts>
struct collapse<std::enable_if_t<!is_broken_v<T>>, T, broken_t, Ts...> :
collapse<void, T, Ts...> {};
template<typename... Ts>
struct collapse<void, broken_t, Ts...> :
collapse<void, Ts...> {};
template<typename T, typename... Ts>
struct collapse<std::enable_if_t<!is_broken_v<T>>, T, T, Ts...> :
collapse<void, T, Ts...> {};
template<typename... Ts>
using collapse_t = typename collapse<void, Ts...>::type;
template<typename, typename>
struct unique_call;
template<typename T, size_t... Ns>
struct unique_call<T, std::index_sequence<Ns...>>
{
using type = collapse_t<call_t<T, Ns>...>;
};
template<typename T, size_t N = 10>
using unique_call_t = typename unique_call<T, std::make_index_sequence<N>>::type;
The following asserts passes
auto f = [](auto x, auto y, int z) -> int {return 42;};
auto g = [](double x, auto y) -> float {return 4.2;};
static_assert(std::is_same_v<int, unique_call_t<decltype(f)>>);
static_assert(std::is_same_v<float, unique_call_t<decltype(g)>>);
Live
The way this works is by "scanning" a type and seeing if any number of arguments can be used to call it. The upper limit of arguments has to be pre-specified, but realistically if someone gives me something with more than ten parameters, I'm just gonna pretend that it doesn't exist anyways :D
The set of possible return types are then checked, if there are different types in there, or if there is none, the resulting type will be broken_t.
struct S
{
int operator()(int);
float operator()(float);
};
struct U {};
static_assert(std::is_same_v<broken_t, unique_call_t<S>>); // passes
static_assert(std::is_same_v<broken_t, unique_call_t<U>>); // passes
Caveats
This method cannot differentiate non-existent operator() and one that is overloaded for the same argument count. The following type will be perceived as only having int operator()().
struct S
{
int operator()();
int operator()(int);
float operator()(float);
};
static_assert(std::is_same_v<int, unique_call_t<S>>); // passes!??
I have yet to think of a method that can do this.
Another problem is with templates
template<typename T, std::enable_if_t<std::is_integral<T>>* = nullptr>
int operator()(T);
Since we cheated and created the type ubiq and used that as a placeholder for arguments, it won't play nice with templates, T won't be an integral in this case.
Unfortunately, there is no way of doing this at the moment, as there is no way of asking the compiler what the developer put after -> in a trailing return type. Maybe reflection could make this possible in the future.
Your best bet is either specifying the argument types or using a type that's implicitly convertible to anything else to simulate an invocation of the lambda:
struct any_type
{
template <typename T>
constexpr operator T() { return *this; }
};
This is not perfect as it doesn't work if the lambda's body tries to invoke a method that any_type doesn't "mock".

Transform typelist with function at runtime

I have a typelist. I would like to create a tuple with the results of calling a function on each type in that list and then use that as arguments to another functor. So something like this:
template<typename F>
struct function_traits;
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...) const> {
using return_type = R;
using param_types = std::tuple<Args...>;
};
template<typename T> struct function_traits : public
function_traits<decltype(&T::operator())> {};
template <typename T>
T* get_arg(int id)
{
// Actual implementation omitted. Uses the id parameter to
// do a lookup into a table and return an existing instance
// of type T.
return new T();
}
template <typename Func>
void call_func(Func&& func, int id)
{
using param_types = function_traits<Func>::param_types>;
func(*get_arg<param_types>(id)...); // <--- Problem is this line
}
call_func([](int& a, char& b) { }, 3);
The problem is that func(*get_arg<param_types>(id)...); doesn't actually compile since param_types is a tuple and not a parameter pack. The compiler generates this error: "there are no parameter packs available to expand". What I would liked to have happened is for that line to expand to:
func(*get_arg<int>(id), *get_arg<char>(id));
And to have that work for any number of arguments. Is there any way to get that result?
This question seems similar but does not solve my problem by itself: "unpacking" a tuple to call a matching function pointer. I have a type list and from that I want to generate a list of values to use as function arguments. If I had the list of values I could expand them and call the function as outlined in that question, but I do not.
Not sure that is what do you want.
I don't know how to expand, inside call_func(), the parameters pack of params_type but, if you afford the use of a helper struct and a compiler with C++14...
I've prepared the following example with support for return type.
#include <tuple>
template<typename F>
struct function_traits;
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...) const> {
using return_type = R;
using param_types = std::tuple<Args...>;
};
template<typename T> struct function_traits : public
function_traits<decltype(&T::operator())> {};
template <typename T, typename ... Args>
T get_arg (std::tuple<Args...> const & tpl)
{ return std::get<typename std::decay<T>::type>(tpl); }
template <typename ...>
struct call_func_helper;
template <typename Func, typename Ret, typename ... Args>
struct call_func_helper<Func, Ret, std::tuple<Args...>>
{
template <typename T, typename R = Ret>
static typename std::enable_if<false == std::is_same<void, R>::value, R>::type
fn (Func const & func, T const & t)
{ return func(get_arg<Args>(t)...); }
template <typename T, typename R = Ret>
static typename std::enable_if<true == std::is_same<void, R>::value, R>::type
fn (Func const & func, T const & t)
{ func(get_arg<Args>(t)...); }
};
template <typename Func,
typename T,
typename R = typename function_traits<Func>::return_type>
R call_func (Func const & func, T const & id)
{
using param_types = typename function_traits<Func>::param_types;
return call_func_helper<Func, R, param_types>::fn(func, id);
}
int main()
{
call_func([](int const & a, char const & b) { }, std::make_tuple(3, '6'));
return 0;
}
Hope this helps.

Type trait for member template static function

I have a problem with type traits in C++. I'm used to make SFINAE checks to ensure that a function exist or not. However, I would like to have a trait that can tell if a class has a specific template member static function.
This example will help explain my problem. Let's pretend that the doMake function takes a function pointer as parameter and its arguments as a pack.
struct A {
static A construct(int mA, double mB) {
return A{mA, mB};
}
int a;
double b;
};
struct B {
// silly but some of my code need this
template<typename T>
static B construct(int mA, T mB) {
return B{mA, mB};
}
int a;
double b;
};
struct Container {
// function (1)
template<typename T, typename... Args,
typename std::enable_if<has_template_construct<T>::value, int>::type = 0>
T make(Args&&... args) {
return doMake(&T::construct<Args...>, std::forward<Args>(args)...);
}
// function (2)
template<typename T, typename... Args,
typename std::enable_if<has_construct<T>::value, int>::type = 0>
T make(Args&&... args) {
return doMake(&T::construct, std::forward<Args>(args)...);
}
// function (3)
template<typename T, typename... Args,
typename std::enable_if<!has_construct<T>::value, int>::type = 0>
T make(Args&&... args) {
return T{std::forward<Args>(args)...};
}
};
// ...
int main() {
Container c;
auto a = c.make<A>(1, 5.7); // would call (2)
auto b = c.make<B>(2, 5.8); // would call (1)
auto d = C.make<float>(4.f); // obviously call the last
return 0;
}
I know how to implement has_construct, but I'm quite lost at how to implement has_template_construct. Can someone give me some hints?
Thanks!
With experimental is_detected you may do:
template<class T>
using construct_t = decltype(&T::construct);
template<class T, typename...Ts>
using template_construct_t = decltype(&T::template construct<Ts...>);
template <typename T>
using has_construct = is_detected<construct_t, T>;
template <typename T, typename...Ts>
using has_template_construct = is_detected<template_construct_t, T, Ts...>;
Note that in function1, you will have to use has_template_construct<T, Args...>::value (,Args... added).

From typelist to argument pack

I have a typelist of the form described here:
http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813
Each type has a duck-typed function (template/compile-time virtual) called get() which returns a simple type like this:
struct Float {
float get() { return 7.0; }
};
struct Int {
int get() { return 7; }
};
typedef typelist<Float, typelist<Int, null_typelist>> types;
I also have a function that takes a variadic number of simple type arguments, like this:
template<typename... Args>
foo(Args... args)
{
}
Now I need a way to call foo given types. I think there's a solution to this, via a tuple, but I'm really far from a solution that works...
I hope you can help me here!
This code converts typelist to tuple and calls foo with simple types.
#include <tuple>
#include <iostream>
template<typename H, typename T>
struct typelist
{
typedef H Head;
typedef T Tail;
};
struct null_typelist {};
template<int... Indices>
struct indices {
using next = indices<Indices..., sizeof...(Indices)>;
};
template<int Size>
struct build_indices {
using type = typename build_indices<Size - 1>::type::next;
};
template<>
struct build_indices<0> {
using type = indices<>;
};
template<typename T>
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template<typename Tuple>
constexpr
typename build_indices<std::tuple_size<Bare<Tuple>>::value>::type
make_indices()
{ return {}; }
template<typename T, typename... Args>
struct tuple_push;
template<typename T, typename... Args>
struct tuple_push<T, std::tuple<Args...>>
{
typedef std::tuple<Args..., T> type;
};
template<typename TL>
struct typelist_to_tuple;
template<typename H, typename T>
struct typelist_to_tuple<typelist<H, T>>
{
typedef typename tuple_push<H, typename typelist_to_tuple<T>::type>::type type;
};
template<typename H>
struct typelist_to_tuple<typelist<H, null_typelist>>
{
typedef std::tuple<H> type;
};
struct Float {
float get() const { return 7.5; }
};
struct Int {
int get() const { return 7; }
};
template<typename... Args>
void foo(const Args&... args)
{
}
template<typename T, typename... Args>
void foo(const T& current, const Args&... args)
{
std::cout << current << std::endl;
foo(args...);
}
template<typename Tuple, int... Indices>
void apply(const Tuple& tuple, indices<Indices...>)
{
foo(std::get<Indices>(tuple).get()...);
}
template<typename Tuple>
void apply(const Tuple& tuple)
{
apply(tuple, make_indices<Tuple>());
}
int main()
{
typedef typelist<Int, typelist<Float, typelist<Int, null_typelist>>> list;
typedef typelist_to_tuple<list>::type tuple;
tuple t = std::make_tuple(Int(), Float(), Int());
apply(t);
}
live example
I think this can be done without using std::tuple. As others have mentioned, C++11 and onwards support typelists based on parameter packs, which are much easier to work with than the C++03 recursive typelists:
template <typename...>
struct tlist {};
Assuming the C++03 typelists are part of an API that you can't change, the first thing is to convert the C++03 typelist to a C++11 typelist. That can be done with some empty function declarations acting as type functions:
// Concatenate two tlist types
template <typename... Ts, typename... Us>
static auto concat_impl(tlist<Ts...>, tlist<Us...>) -> tlist<Ts..., Us...>;
// Base case
static auto to_tlist_impl(null_typelist) -> tlist<>;
// Recursive case
template <typename Head, typename Tail>
static auto to_tlist_impl(typelist<Head, Tail>)
-> decltype(concat_impl(tlist<Head>{}, to_tlist_impl(Tail{})));
// Alias template to make usage easier
template <typename Typelist>
using to_tlist = decltype(to_tlist_impl(Typelist{}));
Next, provide a helper function to take the parameter pack out of a tlist and pass it to the foo function. The original question did not specify how the types should be constructed, so here they are just default constructed as they are passed in to foo.
template <typename... Ts>
void call_foo(tlist<Ts...>) {
foo(Ts{}...);
}
Finally, to call foo with a recursive typelist type just convert it to a tlist with the to_tlist type function:
using list = typelist<Int, typelist<Float, typelist<String, null_typelist>>>;
call_foo(to_tlist<list>{});
Godbolt example: https://godbolt.org/z/j8P55v7Kb