C++11 way to index tuple at runtime without using switch

I have a piece of c++11 code similar like below:

switch(var) {
   case 1: dosomething(std::get<1>(tuple));
   case 2: dosomething(std::get<2>(tuple));
   ...
}

Is there any way to remove this large switch ? Note that get<var> does not work because var is not constant, but I know var is in small range i.e. (0-20).

Note that the point here is to avoid using an array that causes an array lookup...

EDIT:

well on the issue of performance, there is a discussion Performance of array of functions over if and switch statements

For my own purpose, I do not argue which one is better.

Here's a version that doesn't use an index sequence:

template <size_t I>
struct visit_impl
{
    template <typename T, typename F>
    static void visit(T& tup, size_t idx, F fun)
    {
        if (idx == I - 1) fun(std::get<I - 1>(tup));
        else visit_impl<I - 1>::visit(tup, idx, fun);
    }
};

template <>
struct visit_impl<0>
{
    template <typename T, typename F>
    static void visit(T& tup, size_t idx, F fun) { assert(false); }
};

template <typename F, typename... Ts>
void visit_at(std::tuple<Ts...> const& tup, size_t idx, F fun)
{
    visit_impl<sizeof...(Ts)>::visit(tup, idx, fun);
}

template <typename F, typename... Ts>
void visit_at(std::tuple<Ts...>& tup, size_t idx, F fun)
{
    visit_impl<sizeof...(Ts)>::visit(tup, idx, fun);
}

DEMO

C (programming language), C programming is a general-purpose, procedural, imperative computer programming language developed in 1972 by Dennis M. Ritchie at the Bell Telephone  C or c is the third letter in the English and ISO basic Latin alphabets. Its name in English is cee, plural cees.

Here's an unreadably over-generic implementation without recursion. I don't think I'd use this in production - it's a good example of write-only code - but it's interesting that it can be done. (DEMO):

#include <array>
#include <cstddef>
#include <initializer_list>
#include <tuple>
#include <iostream>
#include <type_traits>
#include <utility>

template <std::size_t...Is> struct index_sequence {};

template <std::size_t N, std::size_t...Is>
struct build : public build<N - 1, N - 1, Is...> {};

template <std::size_t...Is>
struct build<0, Is...> {
    using type = index_sequence<Is...>;
};

template <std::size_t N>
using make_index_sequence = typename build<N>::type;

template <typename T>
using remove_reference_t = typename std::remove_reference<T>::type;

namespace detail {
template <class Tuple, class F, std::size_t...Is>
void tuple_switch(const std::size_t i, Tuple&& t, F&& f, index_sequence<Is...>) {
  [](...){}(
    (i == Is && (
       (void)std::forward<F>(f)(std::get<Is>(std::forward<Tuple>(t))), false))...
  );
}
} // namespace detail

template <class Tuple, class F>
void tuple_switch(const std::size_t i, Tuple&& t, F&& f) {
  static constexpr auto N =
    std::tuple_size<remove_reference_t<Tuple>>::value;

  detail::tuple_switch(i, std::forward<Tuple>(t), std::forward<F>(f),
                       make_index_sequence<N>{});
}

constexpr struct {
  template <typename T>
  void operator()(const T& t) const {
      std::cout << t << '\n';
  }
} print{};

int main() {

  {
    auto const t = std::make_tuple(42, 'z', 3.14, 13, 0, "Hello, World!");

    for (std::size_t i = 0; i < std::tuple_size<decltype(t)>::value; ++i) {
      tuple_switch(i, t, print);
    }
  }

  std::cout << '\n';

  {
    auto const t = std::array<int, 4>{{0,1,2,3}};
    for (std::size_t i = 0; i < t.size(); ++i) {
      tuple_switch(i, t, print);
    }
  }
}

C Programming Tutorial for Beginners, C Language - Overview - C is a general-purpose, high-level language that was originally developed by Dennis M. Ritchie to develop the UNIX operating system​  Stock analysis for Citigroup Inc (C:New York) including stock price, stock chart, company news, key statistics, fundamentals and company profile.

It's possible but it's pretty ugly:

#include <tuple>
#include <iostream>

template<typename T>
void doSomething(T t) { std::cout << t << '\n';}

template<int... N>
struct Switch;

template<int N, int... Ns>
struct Switch<N, Ns...>
{
  template<typename... T>
    void operator()(int n, std::tuple<T...>& t)
    {
      if (n == N)
        doSomething(std::get<N>(t));
      else
        Switch<Ns...>()(n, t);
    }
};

// default
template<>
struct Switch<>
{
  template<typename... T>
    void operator()(int n, std::tuple<T...>& t) { }
};

int main()
{
  std::tuple<int, char, double, int, int, const char*> t;
  Switch<1, 2, 4, 5>()(4, t);
}

Just list each constant that would have been a case label in the original switch in the template argument list for the Switch specialization.

For this to compile, doSomething(std::get<N>(t)) must be a valid expression for every N in the argument list of the Switch specialization ... but that's true of the switch statement too.

For a small number of cases it compiles to the same code as a switch, I didn't check if it scales to large numbers of cases.

If you don't want to type out every number in Switch<1, 2, 3, 4, ... 255> then you could create a std::integer_sequence and then use that to instantiate the Switch:

template<size_t... N>
Switch<N...>
make_switch(std::index_sequence<N...>)
{
  return {};
}

std::tuple<int, char, double, int, int, const char*> t;
make_switch(std::make_index_sequence<4>{})(3, t);

This creates a Switch<0,1,2,3> so if you don't want the 0 case you'd need to manipulate the index_sequence, e.g. this chops the zero off the front of the list:

template<size_t... N>
Switch<N...>
make_switch(std::index_sequence<0, N...>)
{
  return {};
}

Unfortunately GCC crashes when trying to compile make_index_sequence<255> as it involves too much recursion and uses too much memory, and Clang rejects it by default too (because it has a very low default for -ftemplate-instantiation-depth) so this isn't a very practical solution!

"C" Programming Language: Brian Kernighan, C is a powerful general-purpose programming language. It can be used to develop software like operating systems, databases, compilers, and so on. C-- (pronounced cee minus minus) is a C -like programming language. Its creators, functional programming researchers Simon Peyton Jones and Norman Ramsey, designed it to be generated mainly by compilers for very high-level languages rather than written by human programmers.

Learn C, The best site for C and C++ programming. Popular, beginner-friendly C and C++ tutorials to help you become an expert! This is a list of operators in the C and C++ programming languages.All the operators listed exist in C++; the fourth column "Included in C", states whether an operator is also present in C. Note that C does not support operator overloading.. When not overloaded, for the operators &&, ||, and , (the comma operator), there is a sequence point after the evaluation of the first operand.

No need to get all cray cray in c++17.

template <class Func, class Tuple, size_t N = 0>
inline void runtime_get(Func func, Tuple& tup, size_t idx) {
    if (N == idx) {
        std::invoke(func, std::get<N>(tup));
        return;
    }

    if constexpr (N + 1 < std::tuple_size_v<Tuple>) {
        return runtime_get<Func, Tuple, N + 1>(func, tup, idx);
    }
}

And runtime tuple_element for fun.

// Returns a pointer to the type, so the element is not initialized.
template <class Tuple, class Func, size_t N = 0>
inline void runtime_tuple_element(Func func, size_t idx) {
    if (N == idx) {
        std::tuple_element_t<N, Tuple>* ptr = nullptr;
        std::invoke(func, ptr);
        return;
    }

    if constexpr (N + 1 < std::tuple_size_v<Tuple>) {
        return runtime_tuple_element<Tuple, Func, N + 1>(func, idx);
    }
}

C Tutorial, C is a powerful systems programming language. Learn C with our popular C tutorial, which will take you from the very basics of C all the way through sophisticated  As well as C and Simula's influences, other languages also influenced this new language, including ALGOL 68, Ada, CLU and ML . Initially, Stroustrup's "C with Classes" added features to the C compiler, Cpre, including classes, derived classes, strong typing, inlining and default arguments.

C Language - Overview, C is a computer programming language. That means that you can use C to create lists of instructions for a computer to follow. C is one of thousands of  C++ is a middle-level programming language developed by Bjarne Stroustrup starting in 1979 at Bell Labs.C++ runs on a variety of platforms, such as Windows, Mac OS, and the various versions of UNIX. This C++ tutorial adopts a simple and practical approach to describe the concepts of C++ for beginners to advanded software engineers.. Why to Learn C++. C++ is a MUST for students and working

Learn C Programming, Microsoft C++, C, and Assembler documentation. Learn how to use C++, C, and assembly language to develop applications, services, and tools for your platforms and devices.

Cprogramming.com: Learn C and C++ Programming, C# (pronounced see sharp, like the musical note C♯, but written with the number sign) is a general-purpose, multi-paradigm programming language encompassing strong typing, lexically scoped, imperative, declarative, functional, generic, object-oriented (class-based), and component-oriented programming disciplines. It was developed around 2000 by Microsoft as part of its .NET initiative and

Comments
  • You seem to be asking how to index a tuple at runtime.
  • Have you made any measurements suggesting this change in your code would be worthwhile? I'd think an array lookup is almost certainly faster than 256 separate branches where the CPU cannot accurately predict which branch will be taken.
  • Does your tuple contain different types? Is doSomething overloaded for all the types, or are implicit conversions expected?
  • Oh noes, an array lookup! It's only literally one of the fastest operations it's possible to perform.
  • Use an array. The link you added refers to array of pointers to functions vs call a function depending on a switch. Here you want to call the same function with different values, there is no reason to not use an array.
  • Nice, it didn't occur to me to use the tuple size as the range of indices ... doh.
  • Nice but I think the demo is only working for c++14, something is wrong with c++11 ?
  • @w00d The generic lambda [](auto v) {...} is a C++14 feature. You could write a generic functor instead: struct F { template <class T> operator()(T v) const {...} }; F doSomething;
  • BTW, the DEMO provided with this answer can also work with an arbitrary integer got from stdin, for example (and therefore is not known at compile time). ideone.com/ExUbjK
  • how does this work? how does the compiler know when to stop generating the struct at compile time? how does it know when idx == I-1 at compile time?