HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Dynamically call lambda based on stream input

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
streamdynamicallyinputcallbasedlambda

Problem

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

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
    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
    void call(Action action, std::unique_ptr& row)
    {
        typedef CallerTraits   trait;
        typedef typename trait::AllArgs         AllArgs;
        Caller::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 
struct CallerTraits
    : public CallerTraits
{};

template
struct CallerTraits
{
    static const int                        size = sizeof...(Args);
    typedef std::tuple             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
struct Caller
{
static void call(Action action, st

Solution

I would have probably applied the following changes:

  • Make size a static constexpr variable in CallerTraits instead of simply static const.



-
Wherever a function simply passes variadic arguments whose types have been deduced, I would have passed args by universal reference (now officially called forwarding reference) and used std::forward to forward the results to the following functions:

template
void doCall(Action action, std::unique_ptr& row, Args&&... args)
{
    Caller::call(action, row, std::forward(args)...);
}


It's a bit hard and quite long to explain how it works exactly - you can find a great explanation in the answer linked above -, but the main point is that using this particular recipe implements perfect forwarding:

template
void foo(X&& arg)
{
    bar(std::forward(arg));
}


The type of the parameters of X&&... in foo will have the same const and reference qualifications than the type of the corresponding parameters in bar. Anyway, the link is by far clearer than I am. Simply remember the recipe and that for this recipe to work, the type X has to be deduced by the function; it may not work if X is known from somewhere else.

-
Instead of creating functions that take a std::unique_ptr& parameters, I would have had Caller::call and doCall them take a ResultSetRow& and dereferenced row right away. I don't know what is the exact return type of results->getNextRow() so I won't try to assume anything about it and the type that the main call should take as a parameter.

Code Snippets

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, std::forward<Args>(args)...);
}
template<typename X>
void foo(X&& arg)
{
    bar(std::forward<X>(arg));
}

Context

StackExchange Code Review Q#45310, answer score: 18

Revisions (0)

No revisions yet.