Use int-templated function with non-constexpr values

Viewed 55

I have some function

template<int N>
auto foo();

I want to call this function with template parameters that are unknown at compile time, but they can only be numbers 1 to c (where c is a fixed constant, e.g. 10). Is there a better general solution to this problem than the following?

auto foo(int n)
{
  switch(n) {
    case 1:
      return foo<1>();
    case 2:
      return foo<2>();
...
    case 10:
      return foo<10>();
  }
}

This solution is getting quite verbose if the function shall be used for a larger set of integers.

This template parameter is necessary because the function uses a class with such a template argument where this is used for the size of a static-sized array. But this should not be really relevant for the problem. I cannot change the templated version.

2 Answers

Sure:

template <int... Ns>
decltype(auto) dispatch_foo(int const n, std::integer_sequence<int, Ns...>) {
    static constexpr void (*_foos[])() { &foo<Ns>... };
    return _foos[n]();
}

template <int Nmax>
decltype(auto) dispatch_foo(int const n) {
    return dispatch_foo(n, std::make_integer_sequence<int, Nmax>{});
}

Usage:

dispatch_foo<c>(n);

See it live on Wandbox

If you can call an addition helper function, what about using a sequence of integers (from std::make_integer_sequence<MAX>{}) where MAX-1 is max value for your integer value) combined with template folding, ternary operator and comma operator?

I mean... what about as follows?

#include <iostream>
#include <utility>

template <int N>
void foo ()
 { std::cout << N << '\n'; }

template <int ... Is>
void foo (int n, std::integer_sequence<int, Is...>)
 { ((n == Is ? (foo<Is>(), 0) : 0), ...); }

void foo (int n)
 { foo(n, std::make_integer_sequence<int, 42>{}); }

int main()
 {
   foo(2); // print 2
   foo(3); // print 3
   foo(5); // print 5
   foo(7); // print 7
 }

If you can use C++20 (so template lambdas) you can avoid the additional (external) function and your foo() can be simply written

void foo (int n)
 { 
   [&]<int ... Is>(std::integer_sequence<int, Is...>)
        { ((n == Is ? (foo<Is>(), 0) : 0), ...); }
    (std::make_integer_sequence<int, 42>{});
 }
Related