0

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);
}
2
  • 4
    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. Commented Aug 26, 2021 at 7:09
  • 1
    For different types you need to use a callback, like here. Commented Aug 26, 2021 at 9:13

1 Answer 1

2

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);
    });
}
Sign up to request clarification or add additional context in comments.

5 Comments

v is not evaluated as constant expression. godbolt.org/z/1bb94v4Gz
v is not compile-time index. it's tuple element
Exactly. Then I cannot use v to get elements from tuple. Or I am missing something in tuple specs
v itself is tuple element at the indexed value passed to the function once the lambda is called. You don't need to v = get<I>(t). Just to use it for some particular purpose
Small suggestion / enhancement: you can easily support functions that return something else than void simply by using std::array for the table member of runtime_get_func_table. Just replace the current declaration by static constexpr std::array table = {&applyForIndex<Tuple, F, Indices>...}; and make applyForIndex return decltype(auto).

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.