Reputation: 3799
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?
Upvotes: 1
Views: 1758
Reputation: 3799
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
.
Upvotes: 2