Some context: I have code that looks like this (minor issue noted [here][1]):

 

    Statement  select("SELECT * FROM People WHERE ID > ? AND ID < ?");
    select.execute(1462, 1477, [](int ID, std::string const& person, double item1, float item2){
         std::cout << "Got Row:" 
                   << ID     << ", " 
                   << person << ", " 
                   << item1  << ", " 
                   << item2  << "\n";
     });

Anyway this connects to the MySQL DB and starts pulling data from the server. So inside execute I loop over the results and call the lambda for each row:

        template<typename Action, typename ...Args>
        void execute(Args... param, Action action)
        {
            // STUFF TO SET up connection.
            // Start retrieving rows.
 

            while(row = results->getNextRow())
            {
                call(action, row);
            }
        }

So here row gets a single row from the socket connection with mysql (so it calls the lambda as it receives each row (no pulling the rows into memory first)). So the code I want to review is pulling the data and calling the lambda.

     // Statement::call

        template<typename Action>
        void call(Action action, std::unique_ptr<ResultSetRow>& row)
        {
            typedef CallerTraits<decltype(action)>   trait;
            typedef typename trait::AllArgs         AllArgs;
            Caller<trait::size, 0, AllArgs, Action>::call(action, row);
        }

This utilizes the helper class `CallerTraits` and `Caller` to pull the required rows from the stream and then call the lambda:


    // CallerTraits
    // Get information about the arguments in the lambda

    template <typename T>
    struct CallerTraits
        : public CallerTraits<decltype(&T::operator())>
    {};
    
    template<typename C, typename ...Args>
    struct CallerTraits<void (C::*)(Args...) const>
    {
        static const int                        size = sizeof...(Args);
        typedef std::tuple<Args...>             AllArgs;
    };

Then the `Caller`:    

    // Caller::call()
    //    Reads the next argument required by the lambda from the stream.
    //    An exception will be generated if the next argument on the stream
    //    does not match the type expected by the lambda.
    template<int size, int index, typename ArgumentTupple, typename Action, typename ...Args>
    struct Caller
    {
        static void call(Action action, std::unique_ptr<ResultSetRow>& row, Args... args)
        {
            // Get the next argument type required by the lambda.
            // As defined by index. Then remove all ref and const
            // bindings.
            typedef typename std::tuple_element<index, ArgumentTupple>::type    NextArgBase;
            typedef typename std::remove_reference<NextArgBase>::type           NextArgCont;
            typedef typename std::remove_const<NextArgCont>::type               NextArg;
    
            // Read the next value from the stream.
            NextArg val;
            row->getValue(val);

            // Recursively call Caller::call() (via doCall())
            // To get the next argument we need. All the arguments
            // are accumulated in the var args parameter `args`
            doCall<size-1, index+1, ArgumentTupple>(action, row, args..., val);
        }
    };

Specialization when no more args need to be retrieved:

    // Specialization of Caller::call() when we have got all the arguments.
    // This simply calls the lambda with the arguments we have accumulated.
    template<int index, typename ArgumentTupple, typename Action, typename ...Args>
    struct Caller<0, index, ArgumentTupple, Action, Args...>
    {
        static void call(Action action, std::unique_ptr<ResultSetRow>&, Args... args)
        {
            action(args...);
        }
    };

Function to deduce parameter types:

    // Function template needed because we
    // can not deduce the Args... parameter manually in the call.
    // so we let the compiler deduce it for us.
    template<int size, int index, typename ArgumentTupple, typename Action, typename ...Args>
    void doCall(Action action, std::unique_ptr<ResultSetRow>& row, Args... args)
    {
        Caller<size, index, ArgumentTupple, Action, Args...>::call(action, row, args...);
    }

[1]: https://stackoverflow.com/q/22636151/14065