9

I am trying to write a wrapper make_function, which like std::make_pair can create a std::function object out of suitable callable objects.

Just like make_pair, for a function pointer foo, auto f0 = make_function(foo); creates a std::function function object f0 of the right type signature. Just to clarify, I don't mind occasionally giving type parameters to make_function in case it is difficult (or impossible) to deduce the type entirely from the parameters.

What I came up with so far (code below) works fine for lambdas, some function pointers, and functors (I didn't consider volatiles). But I couldn't get it work for std::bind or std::bind<R> results. In the code below

auto f2 = make_function(std::bind(foo,_1,_2,_3)); //not OK

wouldn't compile/work, with gcc 4.8.1. I am guessing that I didn't capture the operator() for the bind result correctly, but I am not sure how to fix it.

Any help on how to fix this case or improvement in other corner cases is appreciated.

My question is, of course, how to fix the error in the example below.

For background, one of the cases I use this wrapper can be found at this question: How to make C++11 functions taking function<> parameters accept lambdas automatically. If you do not approve the use of std::function or my specific way of using it, please leave your comments in that post, and discuss technical issues here.

--- EDIT ---

From some of the comments, I learned that it's because of the ambiguity issue (ambiguity of the function call operator() of std::bind results). As pointed out by @Mooing Duck's answer, the solution is to give the parameter types explicitly. I have updated the code to combine the three functions in @Mooing Duck's answer (with slight change of type parameters), so that the make_function wrapper can now handle/type-deduce unambiguous cases as before, and allow specification of complete type signature when there is ambiguity.

(My original code for the unambiguous cases is at: https://stackoverflow.com/a/21665705/683218 and can be tested at: https://ideone.com/UhAk91):

#include <functional>
#include <utility>
#include <iostream>
#include <functional>
using namespace std;

// For generic types that are functors, delegate to its 'operator()'
template <typename T>
struct function_traits
  : public function_traits<decltype(&T::operator())>
{};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
  enum { arity = sizeof...(Args) };
  typedef function<ReturnType (Args...)> f_type;
};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) > {
  enum { arity = sizeof...(Args) };
  typedef function<ReturnType (Args...)> f_type;
};

// for function pointers
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType (*)(Args...)>  {
  enum { arity = sizeof...(Args) };
  typedef function<ReturnType (Args...)> f_type;
};

template <typename L> 
static typename function_traits<L>::f_type make_function(L l){
  return (typename function_traits<L>::f_type)(l);
}

//handles bind & multiple function call operator()'s
template<typename ReturnType, typename... Args, class T>
auto make_function(T&& t) 
  -> std::function<decltype(ReturnType(t(std::declval<Args>()...)))(Args...)> 
{return {std::forward<T>(t)};}

//handles explicit overloads
template<typename ReturnType, typename... Args>
auto make_function(ReturnType(*p)(Args...))
    -> std::function<ReturnType(Args...)> {
  return {p};
}

//handles explicit overloads
template<typename ReturnType, typename... Args, typename ClassType>
auto make_function(ReturnType(ClassType::*p)(Args...)) 
    -> std::function<ReturnType(Args...)> { 
  return {p};
}

// testing
using namespace std::placeholders;

int foo(int x, int y, int z) { return x + y + z;}
int foo1(int x, int y, int z) { return x + y + z;}
float foo1(int x, int y, float z) { return x + y + z;}

int main () {
  //unambuiguous
  auto f0 = make_function(foo);
  auto f1 = make_function([](int x, int y, int z) { return x + y + z;});
  cout << make_function([](int x, int y, int z) { return x + y + z;})(1,2,3) << endl;

  int first = 4;
  auto lambda_state = [=](int y, int z) { return first + y + z;}; //lambda with states
  cout << make_function(lambda_state)(1,2) << endl;

  //ambuiguous cases
  auto f2 = make_function<int,int,int,int>(std::bind(foo,_1,_2,_3)); //bind results has multiple operator() overloads
  cout << f2(1,2,3) << endl;
  auto f3 = make_function<int,int,int,int>(foo1);     //overload1
  auto f4 = make_function<float,int,int,float>(foo1); //overload2

  return 0;
}

Ideone

Community
  • 1
  • 1
thor
  • 21,418
  • 31
  • 87
  • 173
  • 5
    Why would you want to do this in the first place? `auto f = std::bind(foo, _1, _2);` is better than the equivalent `std::function`! – David Rodríguez - dribeas Feb 12 '14 at 20:25
  • The reason is that I need `f` to be `std::function` typed for a function parameter. And `std::function` typed variables do not accept `bind` results or other callables acutomatically. – thor Feb 12 '14 at 20:26
  • Besides, this is just something nice to have for completeness, IMO. – thor Feb 12 '14 at 20:30
  • 1
    What do you mean by "std::function typed variables do not accept bind results or other callables acutomatically" Something like that: http://coliru.stacked-crooked.com/a/d66117115e71a7ee ? – Richard Vock Feb 12 '14 at 20:42
  • Here is what I mean: http://stackoverflow.com/questions/20722918/how-to-make-c11-functions-taking-function-parameters-accept-lambdas-automati/ – thor Feb 12 '14 at 20:44
  • @TingL: This isn't possible in the general sense, it's not always possible to deduce the parameter types, especially for functionoids. – Mooing Duck Feb 12 '14 at 20:45
  • So you were referring to lambdas, not the result of std::bind... When it comes to generic lambdas in c++1y this won't work in any way I guess... – Richard Vock Feb 12 '14 at 20:46
  • No, I have solve the problem for lambda, but not for std::bind. I suspect it is possible at least for the based cases. That's why I ask here. – thor Feb 12 '14 at 20:46
  • @MooingDuck. Thanks for pointing that out. I only wanted to cover the basic cases like most functions we see, lambdas, and std::bind of regular functions. That will be good enough for me. Also, I don't mind specifying the types specifically if compiler can't figure it out occasionally. – thor Feb 12 '14 at 20:49
  • @TingL: Also, the linked question was because functions cannot deduce the return type and parameter type of a lambda, which is the exact same problem you're encountering. If you can solve this, that would completely remove the _need_ for this. – Mooing Duck Feb 12 '14 at 21:10
  • @MooingDuck I think I figured it out for lambda about deduction of return and parameter types. But the same technique fails here for std::bind. You are right in a way, this question in technically about how to expand that technique to figure out the type signature of a `std::bind` result. – thor Feb 12 '14 at 21:12
  • I need this as a convenience function, pretty much `make_pair`. I can program without it. – thor Feb 12 '14 at 21:18
  • I don't see what you mean. You can try `auto v = make_function([](int x, int y, int z) { return x + y + z;})(1,2,3);` – thor Feb 12 '14 at 21:31
  • 1
    You keep on going on a quest for something that is both impossible to solve well (and hack solutions will get increasingly bad with C++1y), and the wrong solution to nearly every practical case I have examined where it was trying to be solved. It does not solve lambdas, because `make_function([](auto x, auto y, auto z) { return x + y + z;})` fails (welcome to C++1y!) – Yakk - Adam Nevraumont Feb 12 '14 at 21:31
  • Well, I did depart from my past c++ habits and is investigating functional programming, if that's what you are referring to. I do remember when STL is still shipped around in a bunch of text files, its author claimed that he believed it's the time to go beyond OOP and into functional programming. – thor Feb 12 '14 at 21:38
  • I don't know what to say if you don't like my practice this much. But I don't blame you for feeling it that way. – thor Feb 12 '14 at 21:40
  • 3
    *something nice to have for completion, IMO* What about `make_int` and `make_double`? `make_string`? `make_vector`? The question still stands: *why* do you want a *deduced* `std::function`? Do you have a need for it other than figuring out whether you can achieve it? What you are trying to do really is to apply type-erasure, and pay the associated cost, for no particular reason. Other than the mental exercise you are basically aiming to write a complicated mechanism that will decrease the performance of your application. – David Rodríguez - dribeas Feb 13 '14 at 03:19
  • Those are trivial, so unnecessary. – thor Feb 13 '14 at 03:35
  • More specifically, they accept the types you expect them to accept naturally, e.g. string's accept const char [], so you don't bother. – thor Feb 13 '14 at 03:39
  • @TingL: (A) That edit isn't part of the question and thus doesn't belong there. Put the code on another page and put a comment here that links to it. (B) Your edit has duplicate functions for member pointers, and you've completely broken the one that handles `bind`. My versions don't take the return type, because that can be deduced and is thus never required to be provided for functionoids (including lamdbas). That's what the `decltype(t(std::declval()...))` in my answer _is_. That _is_ the `ReturnType`. – Mooing Duck Feb 13 '14 at 17:06
  • I still can't deduce how your `make_function([](int x, int y, int z) { return x + y + z;});` works, or reproduce it – Mooing Duck Feb 13 '14 at 17:26
  • Strange. I never had an issue with `make_function([](int x, int y, int z) { return x + y + z;});` with my original code, as I told you earlier. You never responded to that until now. Please see original code at http://stackoverflow.com/a/21665705/683218 . – thor Feb 13 '14 at 17:35
  • The original code at ideone: https://ideone.com/UhAk91 runs fine. – thor Feb 13 '14 at 17:42
  • Let me know if you still cannot replicate my results. I switch the order or the ReturnType because I want to be able to explicitly give it when I explicitly give other type parameters. You original code also works by inferring the return type. – thor Feb 13 '14 at 17:45
  • @TingL: I figured it out! I couldn't reproduce it because I was capturing by rvalue reference and you were capturing by value. As a value you could deduce `T::operator()`, but with a reference I had to `std::remove_reference::type::operator()`. Took me a while, but I got it. The code in my answer now deduces all theoretically deducible functionoid signatures, so I deem it complete. – Mooing Duck Feb 13 '14 at 18:11
  • @MooingDuck In that case, please update your answer appropriately. I didn't think my code was broken all along. – thor Feb 13 '14 at 18:13
  • Thanks for your answer btw, and for actually working on it. I did learn from it. And you seem to be the only respondent who really did some work in this post so far. – thor Feb 13 '14 at 18:15
  • Have you considered the consequences of doing something like `void eat_callback(std::function); auto f = make_function([](long) {}); eat_callback(f);`? – Luc Danton Feb 13 '14 at 18:32
  • @LucDanton: `f` would be `std::function&`, passing that to a function expecting `std::function` would do whatever it normally does, regardless of the code in either the question or my answer, wouldn't it? – Mooing Duck Feb 13 '14 at 18:41
  • This looks fairly similar to (my question) http://stackoverflow.com/questions/11893141/inferring-the-call-signature-of-a-lambda-or-arbitrary-callable-for-make-functio – ecatmur Mar 18 '14 at 22:10
  • @ecatmur Indeed, except that my question here is concerned with handling bind objects, which I wasn't able to address earlier as described in the OP. There are also other earlier questions on SO about inferring types of lambda http://stackoverflow.com/questions/3867276/, which inspired my question why playing with the answers therein. By the way, does your answer address the ambiguity in bind object? – thor Mar 18 '14 at 22:50

3 Answers3

7

The problem is your code doesn't handle lambdas, bind, or functionoids properly, your code assumes that all of these take no parameters. To handle these, you'll have to specify the parameter types:

//plain function pointers
template<typename... Args, typename ReturnType>
auto make_function(ReturnType(*p)(Args...))
    -> std::function<ReturnType(Args...)> 
{return {p};}

//nonconst member function pointers
template<typename... Args, typename ReturnType, typename ClassType>
auto make_function(ReturnType(ClassType::*p)(Args...)) 
    -> std::function<ReturnType(Args...)>
{return {p};}

//const member function pointers
template<typename... Args, typename ReturnType, typename ClassType>
auto make_function(ReturnType(ClassType::*p)(Args...) const) 
    -> std::function<ReturnType(Args...)>
{return {p};}

//qualified functionoids
template<typename FirstArg, typename... Args, class T>
auto make_function(T&& t) 
    -> std::function<decltype(t(std::declval<FirstArg>(), std::declval<Args>()...))(FirstArg, Args...)> 
{return {std::forward<T>(t)};}

//unqualified functionoids try to deduce the signature of `T::operator()` and use that.
template<class T>
auto make_function(T&& t) 
    -> decltype(make_function(&std::remove_reference<T>::type::operator())) 
{return {std::forward<T>(t)};}

Variables:

int func(int x, int y, int z) { return x + y + z;}
int overloaded(char x, int y, int z) { return x + y + z;}
int overloaded(int x, int y, int z) { return x + y + z;}
struct functionoid {
    int operator()(int x, int y, int z) { return x + y + z;}
};
struct functionoid_overload {
    int operator()(int x, int y, int z) { return x + y + z;}
    int operator()(char x, int y, int z) { return x + y + z;}
};
int first = 0;
auto lambda = [](int x, int y, int z) { return x + y + z;};
auto lambda_state = [=](int x, int y, int z) { return x + y + z + first;};
auto bound = std::bind(func,_1,_2,_3);

Tests:

std::function<int(int,int,int)> f0 = make_function(func); assert(f0(1,2,3)==6);
std::function<int(char,int,int)> f1 = make_function<char,int,int>(overloaded); assert(f1(1,2,3)==6);
std::function<int(int,int,int)> f2 = make_function<int,int,int>(overloaded); assert(f2(1,2,3)==6);
std::function<int(int,int,int)> f3 = make_function(lambda); assert(f3(1,2,3)==6);
std::function<int(int,int,int)> f4 = make_function(lambda_state); assert(f4(1,2,3)==6);
std::function<int(int,int,int)> f5 = make_function<int,int,int>(bound); assert(f5(1,2,3)==6);
std::function<int(int,int,int)> f6 = make_function(functionoid{}); assert(f6(1,2,3)==6);
std::function<int(int,int,int)> f7 = make_function<int,int,int>(functionoid_overload{}); assert(f7(1,2,3)==6);
std::function<int(char,int,int)> f8 = make_function<char,int,int>(functionoid_overload{}); assert(f8(1,2,3)==6);

http://coliru.stacked-crooked.com/a/a9e0ad2a2da0bf1f The only reason your lambda was succeeding is because it was implicitly convertible to a function pointer because your example doesn't capture any state. Note that my code requires the parameter types for overloaded functions, functionoids with overloaded operator() (including bind), but is now able to deduce all non-overloaded functionoids.

The decltype lines are complicated but they're used to deduce the return types. Notice that in NONE of my tests do I need to specify the return type. Let's break down make_function<short,int,int> down as if T is char(*)(short, int, int):

-> decltype(t(std::declval<FirstArg>(), std::declval<Args>()...))(FirstArg, Args...)
`std::declval<FirstArg>()` is `short{}` (roughly)
-> decltype(t(short{}, std::declval<Args>()...))(FirstArg, Args...)
`std::declval<Args>()...` are `int{}, int{}` (roughly)
-> decltype(t(short{}, int{}, int{})(FirstArg, Args...)
`t(short{}, int{}, int{})` is an `int{}` (roughly)
-> decltype(short{})(FirstArg, Args...)
`decltype(int{})` is `int`
-> int(FirstArg, Args...)
`FirstArg` is still `short`
-> int(short, Args...)
`Args...` are `int, int`
-> int(short, int, int)
So this complex expression merely figures out the function's signature
well, that should look familiar...
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • I tried : `auto v = make_function([](int x, int y, int z) { return x + y + z;})(1,2,3);`, seems to be OK. – thor Feb 12 '14 at 21:36
  • @TingL: There, I figured out lambdas with state, overloaded functions, and overloaded member functions – Mooing Duck Feb 12 '14 at 21:43
  • Thanks for your help. I added your lambda_state test and tried though, lambda_state seems to work fine with the code in OP. Please see the update code. I am using gcc4.8.1 from mingw32. – thor Feb 12 '14 at 22:47
  • Mind explaining `-> std::function()(std::declval()...))(Args...)> ` a little bit? This may be what I have missed. Does this also capture certain `operator()`? – thor Feb 12 '14 at 22:50
  • @TingL: It will capture any functionoid, with any number of parameters. Unfortunately, to use that version, you must also specify the types of the parameters, so it can figure out which overload to use. – Mooing Duck Feb 12 '14 at 23:02
  • @MooingDuck You should name the wrappers for member function pointers something else, as you are only using them for type deduction. At the same time, you could make the correct ones for member functions which add as first argument `ClassType&`. This would allow you to work also to wrap member functions like `&SomeClass::foo`. – Svalorzen Jul 05 '16 at 11:46
  • @Svalorzen: Not quite as easy as I expected, since it appears the stateless lambda is using that overload. – Mooing Duck Jul 06 '16 at 16:54
  • @MooingDuck What about something like this? http://coliru.stacked-crooked.com/a/d9a12a37d61056a8 I've also simplified a bit by removing the FirstArg thing since I guess it's not really needed (at least the asserts pass anyway). Feel free to update your answer using this if you like it. – Svalorzen Jul 06 '16 at 21:26
  • @Svalorzen: I'd actually considered that after your first pass, but I felt they were confusing since they result in a different signature, and hadn't taken the time to figure out if that was ok or not. I think I'd be happier with `make_function(&random_class::foo, r);`, which results in the expected signature, but found it was nontrivial and hadn't finished it. – Mooing Duck Jul 07 '16 at 01:05
  • @MooingDuck Makes sense, I'll try looking into that too. However, I don't find the different signature confusing - on the contrary it specifies clearly that those functions are not actually ever being called. I had to fiddle a bit around with the code before realizing that (since they also "seem" to return a value like all other functions). – Svalorzen Jul 07 '16 at 10:19
  • @MooingDuck How about this? http://coliru.stacked-crooked.com/a/57562ee242b6cce9 I tried with `std::bind` but that was obviously not going to work, so why not use lambdas at that point. – Svalorzen Jul 07 '16 at 12:08
  • @MooingDuck Couldn't edit my previous comment, this is better since I avoid the useless `` http://coliru.stacked-crooked.com/a/d3479dd8a17c657c – Svalorzen Jul 07 '16 at 12:13
6

In general you cannot solve it without the severe restriction that whatever you pass to make_function is only callable with exactly one signature.

What are you going to do with something like:

struct Generic
{
    void operator()() { /* ... */ }
    void operator()() const { /* ... */ }

    template<typename T, typename... Ts>
    T operator()(T&& t, Ts&&...) { /* ... */ }

    template<typename T, typename... Ts>
    T operator()(T&& t, Ts&&...) const { /* ... */ }
};

C++14 generic lambdas will have the same issue.

The signature in std::function is based on how you plan to call it and not on how you construct/assign it.

You cannot solve it for std::bind either, as that has indefinite arity:

void foo() { std::cout << "foo()" << std::endl; }
//...

auto f = std::bind(foo);
f();                 // writes "foo()"
f(1);                // writes "foo()"
f(1, 2, 3, 4, 5, 6); // writes "foo()"
Nevin
  • 4,595
  • 18
  • 24
  • Thanks for your comments. In case of ambiguity, is it possible to specifically specify the result_type and args type in make_function? At present, I wanted to make the basic cases work and leave others for future work. – thor Feb 12 '14 at 20:40
  • @TingL: how is `auto f = std::make_function(Generic())` better than `std::function f = Generic`? – Mooing Duck Feb 12 '14 at 20:46
  • ... or `auto f = std::function(Generic());` – Richard Vock Feb 12 '14 at 20:49
  • Yes, in the worst case, it is probably not much better. But in many ordinary uses cases where the type parameters can be inferred (like current non-generic lambda), it is much better. – thor Feb 12 '14 at 20:55
  • @Nevin, your example `auto f = std::bind(foo);` does not compile in my case. – thor Feb 12 '14 at 21:22
  • `no match for call to '(std::_Bind) ()'` – thor Feb 12 '14 at 21:23
  • Please see my other post http://stackoverflow.com/questions/20722918/how-to-make-c11-functions-taking-function-parameters-accept-lambdas-automati/. Arity wasn't an issue there for lambda's. Admittedly, I am ignoring entirely the issue of default parameters and probably similar issues. – thor Feb 12 '14 at 21:28
  • In c++14, for each lambda with a specific combination of template types, will there be multiple function call operators? – thor Feb 13 '14 at 01:17
2

The big reason why you want to be able to convert lambdas to std::function is because you want two overloads, each taking different signatures.

A good way to solve this involves std::result_of.

Suppose you are making a loop control structure that takes a lambda or other functional. If that functional returns void, you want to loop uncontrolled. If it returns bool or the like, you want to loop while it returns true. If it returns enum ControlFlow, you want to pay attention to the ControlFlow return value (continue or break, say). The function in question takes either the element iterating over, and optionally some extra data (the index in the iteration, maybe some "location" meta-information about the element, etc).

std::result_of would let you pretend to invoke the passed in type with a different number of arguments. A traits class could then figure out which of the above signatures is the "best match", and then route to the implementation that handles that signature (possibly by wrapping the "simpler" cases in a lambda and calling the more complex cases).

Naively, your make_function would could this problem, because you could then simply overload on the various std::function< blah(etc) > cases. But with auto parameters coming down the pipe, and std::bind already doing perfect forwarding, this only handles the easiest cases.

std::result_of traits classes (and possibly related concept matching and requires clauses) and tag dispatching (or SFINAE as a last resort).

The big downside is that you end up having to manage the override order yourself semi-manually. I could see some utility in helper classes where you provide a list of signatures to match, and it either produces a boost::variant or you also produce a canonical output and a conversion method to that canonical output.

The short answer? std::bind's implementation is implementation specific details, but it may involve the equivalent of perfect forwarding of variadic parameter packs, and as such is not suitable for your "get the address of the one and only concrete operator()" technique you are using.

As another example:

template <typename A,typename B> 
vector<B> map(std::function<B (A)> f, vector<A> arr) {
   vector<B> res;
   for (int i=0;i<arr.size();i++) res.push_back(f(arr[i]));
   return res;
}

should be written as:

template<typename expression>
using result = typename std::result_of<expression>::type;
template<typename expression>
using decayed_result = typename std::decay<result<expression>>::type;

template <typename function,typename B> 
vector<decayed_result<function(B)>> map(function&& f, vector<A> const& arr) {
   vector<decayed_result<function(B)>> res;
   res.reserve( arr.size() );
   for (A const& a : arr) {
     res.push_back( f(a) );
   }
   return res;
}

again, result_of is the right solution, not converting things needlessly to std::function.

For fold_right we get:

template<bool b, typename T=void>
using EnableIf = typename std::enable_if<b,T>::type;

template<typename function, typename src, typename dest>
EnableIf<
  std::is_convertible< result<function(src, dest)>, dest >::value,
  std::vector<dest>
>
fold_right( function&& f, std::vector<src> const& v, dest initial )

which again skips any type erasure on f. And if you really want to do type erasure on f, you can do:

template<typename T> struct identity { typedef T type; };
template<typename T> using do_not_deduce = typename identity<T>::type;

template<typename src, typename dest>
std::vector<dest> fold_right( do_not_deduce< std::function<dest(src,dest)> > f, std::vector<src> const& v, dest init );

std::function is a type erasure object. You type erase because you want to use a type somewhere you do not want to carry the type over to. Deducing from a type what kind of resulting type erasure object you should create is almost always the wrong answer, because you have all of the dependency of non-type erased cases, and all of the inefficiency of the type erasure.

make_function's result is dependent the full type of the source, which makes type erasure output almost completely useless.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • I think you misunderstood my reason for converting lambda's to std::function. At least your interpretation is quite different from what I thought or wrote. – thor Feb 12 '14 at 21:47
  • But that aside, thanks for pointing out this implementation issue. I hope that `std::bind`. Hopefully someone will be able to give a long answer to the technical problem. – thor Feb 12 '14 at 21:50
  • 1
    @TingL Provide me with a practical problem that type deducing what `std::function` you want to convert to solves. I'm sure there might be one out there, but I honestly have not met it. I added a solution to the problem that inspired your older post in mine, again replacing any need to deduce a `std::function` type. – Yakk - Adam Nevraumont Feb 12 '14 at 21:58
  • please give specific links. And again, I don't have time for another round of discussion about use case. As I said in the question, please see my other post about usage. If you don't like it, criticize me there. – thor Feb 12 '14 at 22:02
  • It may not be practical for you, I respect that. I use it in my own programming. That's good enough for me. I hope you can tolerate it and the fact that I don't have the time to explain what my code does. – thor Feb 12 '14 at 22:04
  • Just to give you an idea, I wrote sed scripts to extract std::function type signatures from functions before I was able to get a rough make_function. The version I have so far is already helping me a lot. – thor Feb 12 '14 at 22:07
  • It's pointless to argue one valid code should be written in another way just because you like it. However much you show that `result_of` works, you didn't show that one shouldn't use std::function<> where the type signature is easy to read and spelled out. – thor Feb 13 '14 at 01:24
  • Also, you are just as off as many of the folks in that post in second-guessing someone else's intention from a minimal example (the `map` example) specifically made to show a language-level issue, and then dive into how a minimal example could be better written according to the textbook. – thor Feb 13 '14 at 01:29
  • @TingL that is why I asked for an actual example where the type deduction of a lambda or other functor into a type erased `std::function` is a practical problem. If you only give toy examples, and every single toy example is better solved (both efficiently and idiomatically) with other techniques... isn't the possibility that your technique is the wrong approach *in C++* worth considering? Now, it is true that under C++11 the resulting code is not easy to read: but with concepts lite in C++1y the techniques I describe generalize into concepts. Your technique becomes less useful in C++1y. – Yakk - Adam Nevraumont Feb 13 '14 at 02:13
  • it is entirely possible my approach is wrong for everyone. But in my case, clarity is of greater importance because I'd like to use higher order functions. If result_of and the like, the code becomes (just my personal experience) write-only at certain point of time. – thor Feb 13 '14 at 02:34
  • c++1y, with concepts is of course something everyone is looking forward to. But until I see how concepts translate to type readability comparable to the use of std::function (or you can call it with a new name like functor), I guess I am on my own, right? – thor Feb 13 '14 at 02:36
  • Not many people understand the issue of readability since they are proud of being able to write complex code that they can understand only because they write it or remember that how they wrote it. I totally respect that. I just wanted my code to be readable years later for myself, and I don't see if I stick to simple use cases (fixed arity, explicitly spelled types if I have to ...) why such code will become less relevant in the future. – thor Feb 13 '14 at 02:39
  • Another thought is that c++ standards evolve as well. Many structures in the previous standards get deprecated. {Unary,Binary}Function, xxx_ptr. On the other hand, certain naive approaches survive (copying and returning std::vector's by value). People invent entire new features (move semantics) just to accommodate that. That's why I don't consider my simple approach necessarily wrong in the long run. – thor Feb 13 '14 at 02:46