0
votes

Reading for how to access a tuple element in runtime, I fell on the following implementation getting-tuple-elements-with-runtime-index

I tried this myself using gcc 11.2 . I called the API for retrieving the tuple but I get the following error

: In instantiation of 'constexpr std::tuple_element >::type& (* const runtime_get_func_table, std::integer_sequenceunsigned int, 0, 1, 2> >::table [3])(std::tuple&) noexcept': :32:53: required from 'constexpr typename std::tuple_elementstd::remove_reference::type>::type& runtime_get(Tuple&&, size_t) [with Tuple = >std::tuple&; typename std::tuple_elementstd::remove_reference::type>::type = int; typename std::remove_reference::type = >std::tuple; size_t = long unsigned int]' :37:37: required from here :15:35: error: no matches converting function 'get' to type 'const get_func_ptr' {aka >'int& (* const)(class std::tuple&) noexcept'} 15 | static constexpr get_func_ptr table[std::tuple_size::value]={

Find the code below(live demo)

#include <tuple>
#include <utility>
#include <type_traits>
#include <stdexcept>

template<
  typename Tuple,
  typename Indices=std::make_index_sequence<std::tuple_size<Tuple>::value>>
struct runtime_get_func_table;

template<typename Tuple,size_t ... Indices>
struct runtime_get_func_table<Tuple,std::index_sequence<Indices...>>{
    using return_type=typename std::tuple_element<0,Tuple>::type&;
    using get_func_ptr=return_type (*)(Tuple&) noexcept;
    static constexpr get_func_ptr table[std::tuple_size<Tuple>::value]={
        &std::get<Indices>...
    };
};

template<typename Tuple,size_t ... Indices>
constexpr typename
runtime_get_func_table<Tuple,std::index_sequence<Indices...>>::get_func_ptr
runtime_get_func_table<Tuple,std::index_sequence<Indices...>>::table[std::tuple_size<Tuple>::value];

template<typename Tuple>
constexpr
typename std::tuple_element<0,typename std::remove_reference<Tuple>::type>::type&
runtime_get(Tuple&& t,size_t index) {
    using tuple_type=typename std::remove_reference<Tuple>::type;
    if(index>=std::tuple_size<tuple_type>::value)
        throw std::runtime_error("Out of range");
    return runtime_get_func_table<tuple_type>::table[index](t);
}

int main() {
    std::tuple<int ,char,float> t;
    auto  a =  runtime_get(t,0);
}
1
This implementation requires all tuple elements to have the same type, which largely defeats the purpose of tuples in the first place and you compiler error is complaining about it.Timo
For different types you need to use a callback, like here.Vladimir Talybin

1 Answers

1
votes

The example codes can be rewritten. Since multiple return types are not possible in C++, so that you will have to get it via a lambda function passed as an argument. The same approach was also mentioned by the guy in the comment

#include <tuple>
#include <utility>
#include <type_traits>
#include <stdexcept>


template<
  typename Tuple,
  typename F,
  typename Indices=std::make_index_sequence<std::tuple_size<Tuple>::value>>
struct runtime_get_func_table;

template<typename Tuple, typename F, size_t I>
    void applyForIndex(Tuple& t, F f) {
        f(std::get<I>(t));
    }

template<typename Tuple, typename F, size_t ... Indices>
struct runtime_get_func_table<Tuple,F,std::index_sequence<Indices...>>{
    using FuncType = void(*)(Tuple&, F);
    static constexpr FuncType table[]={
        &applyForIndex<Tuple, F, Indices>...
    };
};

template<typename Tuple, typename F>
void runtime_get(Tuple& t,size_t index, F f) {
    using tuple_type=typename std::remove_reference<Tuple>::type;
    if(index>=std::tuple_size<tuple_type>::value)
        throw std::runtime_error("Out of range");
    runtime_get_func_table<tuple_type, F>::table[index](t, f);
}

int main() {
    std::tuple<int ,char, float> t(10, 's', 10.2);
    runtime_get(t, 0, [] (auto& v) {
      // Do something v = get<0>(t);
    });
}