Dynamically call lambda based on stream input: Try 2 Originally asked here: Dynamically call lambda based on stream input

The following version is based heavily on the answer provided by @iavr, though I hope that I have done enough more to make it worth reviewing again.

A way to clean parameters of all declarations:

template&lt;typename Decorated&gt;
struct CleanType
{
    typedef typename std::remove_reference&lt;Decorated&gt;::type     NoRefType;
    typedef typename std::remove_const&lt;NoRefType&gt;::type         BaseType;
};


Get Caller traits of a functor:

template &lt;typename T&gt;
struct CallerTraits
    : public CallerTraits&lt;decltype(&amp;T::operator())&gt;
{};

template&lt;typename C, typename ...Args&gt;
struct CallerTraits&lt;void (C::*)(Args...) const&gt;
{
    static constexpr int                                        size = sizeof...(Args);
    typedef typename std::make_integer_sequence&lt;int, size&gt;      Sequence;
    typedef std::tuple&lt;typename CleanType&lt;Args&gt;::BaseType...&gt;   AllArgs;
};
// Notice the call to `CleanType` to get the arguments I want.
// So that I can create objects of the correct type before passing
// them to the functor:


The actual calling of the functor based on reading data from a stream (via ResultSetRow (but I am sure that can be easily generalized)).

Done in 2 parts:

This is the part you call:

template&lt;typename Action&gt;
void callFunctor(Action action, Detail::ResultSetRow&amp; row)
{
    // Get information about the action.
    // And retrieve how many parameters myst be read from
    // the stream before we call `action()`
    typedef CallerTraits&lt;decltype(action)&gt;  Trait;
    typedef typename Trait::Sequence        Sequence;

    doCall2(action, row, Sequence());
}


Part 2:

Here we extract the parameters from the stream then call the action.

template&lt;typename Action, int... S&gt;
void doCall2(Action action, Detail::ResultSetRow&amp; row, std::integer_sequence&lt;int, S...&gt; const&amp;)
{
    // Create a tupple that holds all the arguments we need
    // to call the functior `action()`
    typedef CallerTraits&lt;decltype(action)&gt;  Trait;
    typedef typename Trait::AllArgs         ArgumentTupple;

    // Use the template parameter pack expansion
    // To read all the values from the stream.
    // And place them in the tuple.
    ArgumentTupple  arguments(row.getValue1&lt;typename std::tuple_element&lt;S, ArgumentTupple&gt;::type&gt;()...);

    // Use the template parameter pack expansion
    // To call the function expanding the tupple into
    // individual parameters.
    action(std::get&lt;S&gt;(arguments)...);
}


Example usage:

// Using `ResultRowSet` from below.
int main()
{
    std::stringstream    stream("1 Loki 12.3 2.2");
    Detail::ResultRowSet row(stream); 
    callFunctor([](int ID, std::string const&amp; person, double item1, float item2){
        std::cout &lt;&lt; "Got Row:" 
                  &lt;&lt; ID     &lt;&lt; ", " 
                  &lt;&lt; person &lt;&lt; ", " 
                  &lt;&lt; item1  &lt;&lt; ", " 
                  &lt;&lt; item2  &lt;&lt; "\n";
    }, row);
}


Here it will read an int (ID), a std::string (person) a double (item1) and a float (item2) from the stream (represented by row), then call the lambda provided.

This is not the actual implementation of Detail::ResultSetRow. But for code review purposes you can think of it as:

namespace Detail
{
    class ResultRowSet
    {
        std::istream&amp;   stream;

        public:
            ResultRowSet(std::istream&amp; s)
                : stream(s)
            {}
            template&lt;typename T&gt;
            T getValue1()
            {
                  T  val;
                  stream &gt;&gt; val;
                  return val;
            }
    };
}
It is becoming really good, but there are still a few things that can be done:


There already is a standard way to "clean" a type: std::decay. It does a little bit more than just removing the reference and the const qualification though, but it does basically what you need. Therefore, you can totally get rid of CleanType and use std::decay instead:

using AllArgs = std::tuple&lt;typename std::decay&lt;Args&gt;::type...&gt;;


And since you are using C++14 (I assume this because of std::integer_sequence), you can even use std::decay_t instead:

using AllArgs = std::tuple&lt;std::decay_t&lt;Args&gt;...&gt;;

N3887 also made its way to the C++14 standard. Therefore, if you actually use C++14, you will be able to use the alias template std::tuple_element_t instead of the metafunction std::tuple_element:

ArgumentTupple arguments(row.getValue1&lt;std::tuple_element_t&lt;S, ArgumentTupple&gt;&gt;()...);

This line looks kind of wrong:

typedef typename std::make_integer_sequence&lt;int, size&gt;      Sequence;


When I tried to compile your example, it didn't compile at first because of the typename in this line. std::make_integer_sequence is an alias template, there shouldn't be a typename before it.
You sometimes use ResultRowSet and use ResultSetRow at some other places. It's probably a typo or something like that :p
ArgumentTupple also feels like a typo. It should probably be ArgumentTuple.
std::integer_sequence does not contain anything. Therefore, there is no need to pass is by const&amp;, you can simply pass it by value.