AFAIU get
tries to bind runtime info (column name) to compile-time info (column type)
possible options:
use std::variant<_TArgs...>
as a return type of get
see C++11 way to index tuple at runtime without using switch
the user provides _Ty
type and get
checks at runtime if _Ty
matches the actual type of the column. if yes - return the value and if not - throw an exception
both options:
template<typename... _TArgs>
class result_row {
private:
std::tuple<_TArgs...> m_columns;
static constexpr size_t m_column_count = sizeof...(_TArgs);
// The column names will be filled out after the query is executed.
std::array<std::string, m_column_count> m_column_names;
template <size_t N = 0>
std::variant<_TArgs...> runtime_get(size_t idx) {
if (N == idx) {
return std::variant<_TArgs...>(std::in_place_index_t<N>(), std::get<N>(m_columns));
}
if constexpr (N + 1 < m_column_count) {
return runtime_get<N + 1>(idx);
}
return std::variant<_TArgs...>();
}
template <class T, size_t N = 0>
T runtime_get_typed(std:: size_t idx) {
if (N == idx) {
if constexpr (std::is_same_v<T, std::tuple_element_t<N, std::tuple<_TArgs...>>>)
{
return std::get<N>(m_columns);
}
else
{
throw std::runtime_error("invalid column type");
}
}
if constexpr (N + 1 < m_column_count) {
return runtime_get_typed<T, N + 1>(idx);
}
return T();
}
public:
std::variant<_TArgs...> get(std::string col_name) {
auto it = std::find(std::begin(m_column_names), std::end(m_column_names), col_name);
if (it == std::end(m_column_names)) throw std::runtime_error("invalid column name: " + col_name);
return runtime_get(std::distance(std::begin(m_column_names), it));
}
template <class T>
T get_typed(std::string col_name) {
auto it = std::find(std::begin(m_column_names), std::end(m_column_names), col_name);
if (it == std::end(m_column_names)) throw std::runtime_error("invalid column name: " + col_name);
return runtime_get_typed<T>(std::distance(std::begin(m_column_names), it));
}
};
a working example for both options