Here is quite nice (not mine) example how u can expand (or "explode") tuple as arguments to function:
template<int ...I> struct index_tuple_type {
template<int N> using append = index_tuple_type<I..., N>;
};
template<int N> struct make_index_impl {
using type = typename make_index_impl<N-1>::type::template append<N-1>;
};
template<> struct make_index_impl<0> { using type = index_tuple_type<>; };
template<int N> using index_tuple = typename make_index_impl<N>::type;
template <typename I, typename ...Args>
struct func_traits;
template <typename R, int ...I, typename ...Args>
struct func_traits<R, index_tuple_type<I...>, Args...> {
template <typename TT, typename FT>
static inline R call(TT &&t, FT &&f) {
return f(std::get<I>(std::forward<TT>(t))...);
}
};
template<
typename FT,
typename ...Args,
typename R = typename std::result_of<FT(Args&&...)>::type
>
inline R explode(std::tuple<Args...>& t, FT &&f) {
return func_traits<R, index_tuple<sizeof...(Args)>, Args...>
::call(t, std::forward<FT>(f));
}
then you can use this like so:
void test1(int i, char c) {
printf("%d %c\n", i, c);
}
int main() {
std::tuple<int, char> t1{57, 'a'};
explode(t1, test1);
}
Live version
I was wandering how could you do the same thing with std::array since it quite like tuple. std::get<N> works with std::array so I thought that it would be easy to modify this solution. But something like this doesn't work:
template<
typename FT,
typename Arg,
std::size_t I,
typename R = typename std::result_of<FT(Arg&&)>::type
>
inline R explode(std::array<Arg, I>& t, FT &&f) {
return func_traits<R, index_tuple<I>, Arg>::
call(t, std::forward<FT>(f));
}
void test2(int i1, int i2) {
printf("%d %d\n", i1, i2);
}
int main() {
std::array<int, int> t1{1, 2};
explode(t2, test1);
}
because of the part std::result_of<FT(Arg&&)>::type. The argument type Arg&& is wrong and result_of has no field type. For tuple Args&&... expanded, but now it should be "repeated" I times. Is there a way to do this using result_of so the returned type can be deducted?
Also i was wondering, having the tools to "unpack" tuple and array would it be possible to "unpack" recursively (probably using enable_if) structure like tuple<array<int, 2>, tuple<array<double,3>, ... and so on? Some kind of a tree where tuple and array are branches, and other types are leaves?
// enable argument dependent lookup on `get` call:
namespace aux {
using std::get;
template<size_t N, class T>
auto adl_get( T&& )->decltype( get<N>(std::declval<T>()) );
}
using aux::adl_get;
template<class F, class TupleLike, size_t...Is>
auto explode( F&& f, TupleLike&& tup, std::index_sequence<Is...> )
-> std::result_of_t< F( decltype(adl_get<Is>(std::forward<TupleLike>(tup)))... ) >
{
using std::get; // ADL support
return std::forward<F>(f)( get<Is>(std::forward<TupleLike>(tup))... );
}
is the first step. std::index_sequence is C++14, but it is easy to implement in C++11.
The next steps are also easy.
First, a traits class that dictates what types are tuple-like. I would go ahead and just duck-type use them, but a number of functions and traits classes we are going to use are not SFINAE friendly:
template<class T>
struct tuple_like:std::false_type{};
template<class... Ts>
struct tuple_like<std::tuple<Ts...>>:std::true_type{};
template<class... Ts>
struct tuple_like<std::pair<Ts...>>:std::true_type{};
template<class T, size_t N>
struct tuple_like<std::array<T,N>>:std::true_type{};
Next, an overload of explode that only works on tuple_like types:
template<class F, class TupleLike,
class TupleType=std::decay_t<TupleLike>, // helper type
class=std::enable_if_t<tuple_like<TupleType>{}>> // SFINAE tuple_like test
auto explode( F&& f, TupleLike&& tup )
-> decltype(
explode(
std::declval<F>(),
std::declval<TupleLike>(),
std::make_index_sequence<std::tuple_size<TupleType>{}>{}
)
)
{
using indexes = std::make_index_sequence<std::tuple_size<TupleType>{}>;
return explode(
std::forward<F>(f),
std::forward<TupleLike>(tup),
indexes{}
);
}
If you lack constexpr support you need to change some {} to ::value .
The above does the trick for pairs, arrays or tuples. If you want to add support for other tuple-like types, simply add a specialization to tuple_like and ensure std::tuple_size is specialized properly for your type and get<N> is ADL-overloaded (in the type's enclosing namespace).
std::make_index_sequence is also C++14 but easy to write in C++11.
template<size_t...>
struct index_sequence{};
namespace details {
template<size_t count, size_t...Is>
struct mis_helper:mis_helper<count-1, count-1, Is...> {};
template<size_t...Is>
struct mis_helper<0,Is...> {
using type=index_sequence<Is...>;
};
}
template<size_t count>
using make_index_sequence=typename details::mis_helper<count>::type;
(this is poor QOI for a C++14 library, which should use at least log descent, as it requires O(n) template recursive template instantiations for a list of size n. However, is n is less than a few 100, it won't matter).
std::enable_if_t<?> is C++14, but in C++11 is just typename std::enable_if<?>::type.
Related
I have a set of classes, like A, B, C and a tuple of tuples containing these classes, like this:
struct A {
std::string name{"a"};
};
struct B {
std::string name{"b"};
};
struct C {
std::string name{"c"};
};
// only first items A(), B(), C() do matter, other are arbitrary
auto t = std::make_tuple(
std::make_tuple(A(), 1, 2, 3),
std::make_tuple(B(), 4, 5, 6),
std::make_tuple(C(), 7, 8)
);
My target logic is to select a tuple from a container tuple by match of type of the first element. So, by example above, I want to get string 'b', when calling something like this:
std::string the_b = having_first_of_type<B, decltype(t)>::get().name;
I am trying to get a solution with templates:
// a template for getting first item from N-th tuple int Tuples
template <std::size_t N, typename... Tuples>
using first_of_nth = std::tuple_element<0, std::tuple_element<N, std::tuple<Tuples...>>>;
template <std::size_t N, class T, class... Tuples>
struct having_first_of_type;
template <std::size_t N, class T, class... Tuples>
struct having_first_of_type<N,
typename std::enable_if<std::is_same<T, typename first_of_nth<N, Tuples...>::type>::value, T>::type* = nullptr>
{
static auto& get(const std::tuple<Tuples...>& tuple) {
return std::get<N>(tuple);
}
};
template <std::size_t N, class T, class... Tuples>
struct having_first_of_type<N,
typename std::enable_if<!std::is_same<T, typename first_of_nth<N, Tuples...>::type>::value, T>::type* = nullptr> : having_first_of_type<N-1, T, Tuples...>;
template <std::size_t N, class T, class... Tuples>
struct having_first_of_type<0, T, Tuples...> {}
And I can't form the specializations in the right way. For the first one (std::is_same is true) compiler says: error: expected '>' for position of '= nullptr'. It looks like it does not accept default value for T*, but I am confused why..
What's the error? Or, perhaps there is a better way to get what I want?
UPDATE
below are 2 working solutions: from N. Shead and #n314159 - thank you!
I forgot to mention that I tried to get it using C++14, but the solutions are for C++17.
C++17 is also OK.
Assigning a nullptr where a tyle belongs does not make sense. You should remove that. Further I am not exactly sure, what goes wrong. We can make the whole thing a bit easier by using the std::get version templated on a type not an index, then we don't have to carry the N:
#include <tuple>
#include <type_traits>
#include <iostream>
template<class T, class Tup, bool negated = false>
using first_of = std::enable_if_t<negated ^ std::is_same_v<std::tuple_element_t<0, Tup>, T>>;
template<class T, class= void, class... Tups>
struct first_match_impl;
template<class T, class Tup1, class... Tups>
struct first_match_impl<T, first_of<T, Tup1>, Tup1, Tups...> {
using type = Tup1;
template<class FullTup>
static Tup1& get(FullTup& t) {
return std::get<Tup1>(t);
}
};
template<class T, class Tup1, class... Tups>
struct first_match_impl<T, first_of<T, Tup1, true>, Tup1, Tups...>: first_match_impl<T, void, Tups...> {};
template<class T, class... Tups>
using first_match = first_match_impl<T, void, Tups...>;
template<class T, class... Tups>
auto& get_first_of(std::tuple<Tups...> &t) {
return first_match<T, Tups...>::get(t);
}
int main()
{
std::tuple<std::tuple<int, float>, std::tuple<char, double>> t {{1,2.}, {'A', 4.}};
std::cout << std::get<0>(get_first_of<char>(t)); // prints A
}
Note that this will not compile when you have two exactly identicall tuples in your tuple but will compile if there are different tuples with the same first element (then it will pick the first of them).
EDIT: This inspired me write a small library providing iterator like support for tuples. See here.
You've tried to give a default value in a place where the compiler expects a concrete type.
I'm assuming you want to get the whole inner tuple?
In that case, my attempt at solving this would look something like this:
template <typename T, typename Tuple>
constexpr bool tuple_first_type_is() {
if constexpr (std::tuple_size_v<Tuple> == 0)
return false;
else
return std::is_same_v<T, std::tuple_element_t<0, Tuple>>;
}
template <typename T, std::size_t I, typename NestedTuple>
constexpr decltype(auto) having_first_of_type_impl(NestedTuple&& nested_tuple) noexcept {
using D = std::decay_t<NestedTuple>;
static_assert(I < std::tuple_size_v<D>, "type not found in tuple");
using ith_tuple = std::tuple_element_t<I, D>;
if constexpr (tuple_first_type_is<T, ith_tuple>())
return std::get<I>(std::forward<NestedTuple>(nested_tuple));
else
return having_first_of_type_impl<T, I+1>(std::forward<NestedTuple>(nested_tuple));
}
template <typename T, typename NestedTuple>
constexpr decltype(auto) having_first_of_type(NestedTuple&& nested_tuple) noexcept {
static_assert(std::tuple_size_v<std::decay_t<NestedTuple>> > 0, "empty tuple");
return having_first_of_type_impl<T, 0>(std::forward<NestedTuple>(nested_tuple));
}
Live: http://coliru.stacked-crooked.com/a/aa1637939a5d7d7c
I'm not 100% confident I've done everything correctly with value categories and the like, and there could well be a better way of going about this, but this is the sort of thing I would start off with.
I have a function foo that calls a function bar with a subset of types passed into foo's variadic template. For example:
template <typename... T>
void foo() {
// ...
template <size_t start_idx, typename... T>
using param_pack = /*Parameter pack with T[start_idx]...T[N]*/
auto b = bar<param_pack<2, T...>>();
// ...
}
Is there a way to extract a "sub-parameter pack". In the above case
if T = [int float char double] then param_pack<2, T...> = [char double]
[EDIT]
My goal is to be able to use something like this to match event handlers. For example
struct ev {};
template <typename... T>
struct event : ev {
std::tuple<T...> data_;
event(T&&... d) : data_(std::make_tuple(std::forward<T>(d)...)) {}
};
template <typename... Functor>
struct handler {
std::tuple<Functor...> funcs_;
handler(Functor&&... f) : funcs_(std::make_tuple(std::forward<Functor>(f)...)) {}
void handle_message(ev* e) {
auto ptrs = std::make_tuple(
dynamic_cast<event<param_pack<1, typename function_traits<F>::args>>*>(e)...
);
match(ptrs);
}
};
Here function_traits::args get a parameter pack for the function arguments and match iterates over the the tuple funcs_ checking if the dynamic_cast was successful and executing the first successful function. I already have these implemented.
The handlers are something like
[] (handler* self, <ARGS>) -> void {
// ...
}
I am essentially trying to get rid of the self argument.
Set aside the fact that it lacks a check on the index N for simplicity, here is a possible solution based on a function declaration (no definition required) and an using declaration:
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
The good part of this approach is that you have not to introduce a new type designed around a tuple, then specialize it somehow iteratively.
It follows a minimal, working example that uses the code above:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<2, int, float, char, double>, std::tuple<char, double>>::value, "!");
}
See a full example up and running on wandbox.
The extended version that includes a check on the index N would look like this:
template<std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
That is the type you can see in the first example once wrapped in a std::enable_if_t, nothing more. Again, declaration is enough, no definition required.
EDIT
If you want to use your own class template instead of an std::tuple, you can easily modify the code to do that:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<typename...>
struct bar {};
template<template<typename...> class C, std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), C<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
template<template<typename...> class C, std::size_t N, typename... T>
using subpack = decltype(sub<C, N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<bar, 2, int, float, char, double>, bar<char, double>>::value, "!");
}
EDIT
According to the code added to the question, the solution above is still valid. You should just define your event class as it follows:
struct ev {};
template <typename>
struct event;
template <typename... T>
struct event<std::tuple<T...>>: ev {
// ...
};
This way, when you do this:
event<param_pack<1, typename function_traits<F>::args>>
You still get a tuple out of param_pack (that is the subpack using declaration in my example), but it matches the template partial specialization of event and the parameter pack is at your disposal as T....
This is the best you can do, for you cannot put a parameter pack in an using declaration. Anyway it just works, so probably it can solve your issue.
You may do something like:
template <std::size_t N, typename ... Ts> struct drop;
template <typename ... Ts>
struct drop<0, Ts...>
{
using type = std::tuple<Ts...>;
};
template <std::size_t N, typename T, typename ... Ts>
struct drop<N, T, Ts...>
{
using type = typename drop<N - 1, Ts...>;
};
// Specialization to avoid the ambiguity
template <typename T, typename... Ts>
struct drop<0, T, Ts...>
{
using type = std::tuple<T, Ts...>;
};
Here is a quick but not particularly reusable solution.
template <typename Pack, std::size_t N, std::size_t... Is>
void invoke_bar_impl(std::index_sequence<Is...>) {
bar<std::tuple_element_t<N + Is, Pack>...>();
}
template <std::size_t N, typename... Ts>
void invoke_bar() {
auto indices = std::make_index_sequence<sizeof...(Ts) - N>();
invoke_bar_impl<std::tuple<Ts...>, N>(indices);
}
This question already has answers here:
"unpacking" a tuple to call a matching function pointer
(9 answers)
Closed 5 years ago.
In C++14, you can do something like this:
struct Placeholder
{
template<typename T>
constexpr static T fct(T val) { return val; }
};
int main()
{
constexpr int i{};
auto fct = [](auto&& placeholder) -> decltype(placeholder.fct(i)) { return 5.5f; };
static_assert(fct(Placeholder{}) == 5, "");
}
For the sake of the example, consider that Placeholder::fct is actually manipulating the input type to something else (in the present case the function call is useless).
On the other hand, in C++11, you can simulate generic lambdas by declaring a templated functor. In fact, I could simply pass i to the constructor and store it as a member, like so:
template<typename T>
class Functor
{
T i;
public:
constexpr Functor(T i) : i{ i } {}
template<typename P>
constexpr auto operator()(P&& placeholder) const -> decltype(placeholder.fct(i))
{
return 5.5f;
}
};
int main()
{
constexpr int i{};
constexpr Functor<decltype(i)> fct(i);
static_assert(fct(Placeholder{}) == 5, "");
}
The problem comes when we want the Placeholder to take a variadic number of arguments, like so:
struct Placeholder
{
template<typename... T>
constexpr static auto fct(T... val) -> typename std::common_type<T...>::type
{
return { /* Do something with the values */ };
}
};
In fact, in C++14, we could simply pass the values directly to the lambda:
decltype(placeholder.fct(1, 2, 3))
However, in C++11, since we can't store a variadic number of members in a class, I don't see how I could achieve the exact same result. Any ideas?
From my understanding, a pure C++11 solution can be worked out from #RichardHodges 's idea. You need to recode std::apply by hand. To that end, you also need to recode std::integer_sequence, std::index_sequence and std::make_index_sequence. Let's start with that:
template <typename T, T... Is>
struct integral_sequence {};
template <std::size_t... Is>
using index_sequence = integral_sequence<std::size_t, Is...>;
template <typename Seq, typename T, T... el>
struct append_sequence;
template <typename T, T... el, T... Is>
struct append_sequence<integral_sequence<T, Is...>, T, el...> {
using type = integral_sequence<T, Is..., el...>;
};
namespace details {
template <std::size_t N>
struct make_index_sequence_impl {
private:
using seq = typename make_index_sequence_impl<N-1>::type;
public:
using type = typename append_sequence<seq, std::size_t, N>::type;
};
template <>
struct make_index_sequence_impl<0u> {
using type = index_sequence<0>;
};
template <std::size_t N>
struct make_index_sequence {
using type = typename make_index_sequence_impl<N-1>::type;
};
template <>
struct make_index_sequence<0u> {
using type = index_sequence<>;
};
} // namespace details
template <std::size_t N>
using make_index_sequence = typename details::make_index_sequence<N>::type;
Now, we can tackle the apply implementation. Its goal is to take a tuple as input and forward its content unpacked. For example, apply([](int x, int y) { /* impl */ }, std::make_tuple(0, 2)) is equivalent to [](int x, int y) { /* ... */ }(0, 2)
To do that we first need to dispatch a tuple content to a functor using an index_sequence:
namespace details {
template <typename F, typename Tuple, std::size_t... Is>
auto apply_impl(F&& ftor, Tuple&& tuple, index_sequence<Is...>) -> decltype(std::forward<F>(ftor)(std::get<Is>(tuple)...)) {
return std::forward<F>(ftor)(std::get<Is>(tuple)...);
}
} // namespace details
Then, the exposed apply comes in:
template <typename F, typename Tuple>
template <typename F, typename Tuple>
auto apply(F&& ftor, Tuple&& tuple) -> decltype(details::apply_impl(std::forward<F>(ftor), std::forward<Tuple>(tuple), make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>())){
return details::apply_impl(std::forward<F>(ftor), std::forward<Tuple>(tuple), make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>());
}
Now we can get the behavior you desired by storing a tuple inside your class and using apply to dispatch its content to your placeholder functor:
template <typename... Ts>
class Functor {
std::tuple<Ts...> is;
public:
constexpr Functor(Ts... ts) : is(std::make_tuple(ts...)) {}
template <typename P>
constexpr auto operator()(P&& placeholder) -> decltype(apply(std::forward<P>(placeholder), is)) {
return apply(std::forward<P>(placeholder), is);
}
};
Putting it all together with some examples leads to this Live Demo
Suppose I have an std::function that takes as input N arguments of type T (this can be constructed using some metaprogramming magic; see below), where N is a template parameter. I would like to std::bind the first argument to construct a function with N-1 arguments (e.g. myBind<...>(someValue)). I could not think of a clever metaprogramming trick to do this. Any suggestions?
From Lambda function with number of arguments determined at compile-time:
You can write a template n_ary_function with a nested typedef type. This type can be used as follows:
template <int N> class A {
typename n_ary_function<N, double>::type func;
};
Following the definition of n_ary_function:
template <std::size_t N, typename Type, typename ...Types>
struct n_ary_function {
using type = typename n_ary_function<N - 1, Type, Type, Types...>::type;
};
template <typename Type, typename ...Types>
struct n_ary_function<0, Type, Types...> {
using type = std::function<void(Types...)>;
};
std::bind uses std::is_placeholder to detect placeholders, which means that you can write your own placeholders to use with std::bind by partially specializing std::is_placeholder:
template<int N>
struct my_placeholder { static my_placeholder ph; };
template<int N>
my_placeholder<N> my_placeholder<N>::ph;
namespace std {
template<int N>
struct is_placeholder<::my_placeholder<N>> : std::integral_constant<int, N> { };
}
This makes it possible to get a placeholder from an integer. The rest is simply the standard integer sequence trick:
template<class R, class T, class...Types, class U, int... indices>
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val, std::integer_sequence<int, indices...> /*seq*/) {
return std::bind(f, val, my_placeholder<indices+1>::ph...);
}
template<class R, class T, class...Types, class U>
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val) {
return bind_first(f, val, std::make_integer_sequence<int, sizeof...(Types)>());
}
Demo. std::integer_sequence is technically C++14, but it's easily implementable in C++11 - just search on SO.
#include <functional>
#include <cstddef>
#include <utility>
#include <tuple>
template <std::size_t N, typename Type, typename... Types>
struct n_ary_function
{
using type = typename n_ary_function<N - 1, Type, Type, Types...>::type;
};
template <typename Type, typename... Types>
struct n_ary_function<0, Type, Types...>
{
using type = std::function<void(Types...)>;
};
using placeholders_list = std::tuple<decltype(std::placeholders::_1)
, decltype(std::placeholders::_2)
, decltype(std::placeholders::_3)
, decltype(std::placeholders::_4)
, decltype(std::placeholders::_5)
, decltype(std::placeholders::_6)
, decltype(std::placeholders::_7)
, decltype(std::placeholders::_8)
, decltype(std::placeholders::_9)
, decltype(std::placeholders::_10)
>;
template <typename F>
struct arity;
template <typename R, typename... Args>
struct arity<std::function<R(Args...)>>
{
static constexpr std::size_t value = sizeof...(Args);
};
template <typename F, typename T, std::size_t... Ints>
auto binder(F f, T t, std::index_sequence<Ints...>)
{
return std::bind(f, t,
typename std::tuple_element<Ints, placeholders_list>::type{}...);
}
template <typename F, typename T>
auto myBind(F f, T t)
{
return binder(f, t, std::make_index_sequence<arity<F>::value - 1>{});
}
Tests:
#include <iostream>
void foo(int a, int b, int c, int d, int e)
{
std::cout << a << b << c << d << e << std::endl;
}
int main()
{
n_ary_function<5, int>::type f = foo;
n_ary_function<4, int>::type b = myBind(f, 1);
b(2, 3, 4, 5);
}
DEMO
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.