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