Suppose you have std::tuple
and a function, which modifies on of its values based on the type.
template<typename T, typename Ts...>
void modify(std::tuple<Ts...>& tuple, const T& value)
{
std::get<T>(tuple) = value;
}
Now suppose, you want to log those function calls, i.e. remember the order of modification of values in the tuple. Here is simple mechanism that does that.
void log(std::size_t index)
{
static std::vector<std::size_t> logged_indexes;
logged_indexes.push_back(index)
}
with following helper
// counts until T is same as N'th type of Tuple
template<typename Tuple, typename T, std::size_t N>
struct tuple_type_index_impl;
template<typename T, std::size_t N>
struct tuple_type_index_impl<std::tuple<>, T, N>
{
static constexpr std::size_t value = N;
};
template<typename First, typename... Rest, typename T, std::size_t N>
struct tuple_type_index_impl<std::tuple<First, Rest...>, T, N>
{
static constexpr std::size_t value = std::is_same<First, T>::value
? N
: tuple_type_index_impl<std::tuple<Rest...>, T, N + 1>::value;
};
// helper variable
template<typename Tuple, Typename T>
constexpr std::size_t tuple_type_index_v = typename tuple_type_index_impl<Tuple, T, 0>::value;
we can have this usage
template<typename T, typename Ts...>
void modify(std::tuple<Ts...>& tuple, const T& value)
{
std::get<T>(tuple) = value;
log(tuple_type_index_v<std::tuple<Ts...>, T>);
}
Which is fine for logging purposes. But suppose you would have to, based on the index, access the tuple again. We can convert runtime index to constexpr using a switch
switch (value)
{
case 0: return std::get<0>(tuple);
case 1: return std::get<1>(tuple);
...
}
which can be compiler generated. But is it really the best we can do? In call to log, the index
is still constexpr, so we could move that to template parameter.
template<std::size_t index>
void log()
{
static std::vector<std::size_t> logged_indexes;
logged_indexes.push_back(index);
}
But that won't help, since we are still passing it to the vector. We could (?) sort of build std::index_sequence
, but we would eventually run out of template parameters. Part of me thinks that this can't be done, but the other opposes, since index
is constexpr. Is it possible to develop some kind of std::vector<constexpr std::size_t>
?