1

I have some code that looks like this:

for (const auto& query_result_row : query_result) {
    my_struct.a = query_results_row["a"].as<int>();
    my_struct.b = query_results_row["b"].as<string>();
    // and so forth.
}

In general, there might be quite a number of fields of different types. And that's good, but if a selected field is NULL, this will throw an exception. So instead I've now written this, which is highly awkward and more than a bit error-prone:

for (const auto& query_result_row : query_result) {
    if (!query_results_row["a"].is_null()) {
        my_struct.a = query_results_row["a"].as<int>();
    }
    if (!query_results_row["ab"].is_null()) {
        my_struct.b = query_results_row["b"].as<string>();
    }
    // and so forth.
}

Ick.

Perhaps, I thought, I could make a (templated) function that simplifies this:

for (const auto& query_result_row : query_result) {
    MaybeSet(my_struct.a, query_results_row["a"]);
    MaybeSet(my_struct.b, query_results_row["b"]);
    // and so forth.
}

The problem here is that query_results_row["a"] is itself a templated type, and, moreover, the as() type may not be precisely the same as the my_struct type (e.g., different types of ints) and although I don't see it today, that smells like the sort of thing that some day could lead to an unintended cast.

// Doesn't work.
template <typename valueT, typename postgresFieldT>
void MaybeSet(valueT& my_struct_field, const postgresFieldT& field) {
    if (!field.is_null()) {
        my_struct_field = field.as<valueT>();
    }
}

Any suggestions on a cleaner way to express this idea of setting things if they're not not null but not trying if they are?

1 Answer 1

2

For future generations: I slightly changed the problem and so arrived at a simple solution.

template <typename T>
class SetThing {
    // ...
    void MaybeSet(const pqxx::result::field& field) {
        if (!field.is_null()) {
            SetClean(field.as<T>());
        }
    }
    template <typename asT>
    void MaybeSet(const pqxx::result::field& field) {
        if (!field.is_null()) {
            SetClean(field.as<asT>());
        }
    }
    // ...
}

Usage then becomes

SetThing thing;
thing.MaybeSet(query_result_row["dog"]);
thing.MaybeSet<the_cast_type>(query_result_row["complicated"]);

The second form is used for a handful of complex types (e.g., classes) that I can construct from something simple (say, an int or a string) but which isn't the base (templated) type of the SetThing.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.