Home > Enterprise >  Generic way for template argument checks
Generic way for template argument checks

Time:12-27

I have to following program:

#include <iostream>

#define max_dim 100

template<unsigned IDim>
struct Node{};

int main() {
    uint x;
    std::cout << "Input dimension: ";
    std::cin >> x;
    if(x < max_dim){
        Node<x> node;
    }else{
        std::cout << "False Input.";
    }
}

which does not compile because the expression Node<x> node needs x to be a constant value, which it is not. Because I have a limited amount of possiblities what x can be (it is limited by max_dim) I could of course just use if-conditions or switch-statements, but this would lead to a lot of redundant code (especially because I am doing a bunch of operations for each node).

I am not really able to change the structure of node.

Is there a more elegant way to achieve this??

CodePudding user response:

std::index_sequence might help.

Then several ways to select compile code from runtime value (recursion, folding expression with linear number of checks for index), here using array (O(1) access but linear in memory).

template <std::size_t I>
void f(/*..*/)
{
    Node<I> node;
    // Your code...
}

template <std::size_t... Is>
constexpr std::array<void(*)(/*..*/), sizeof...(Is)>
make_funcs(std::index_sequence<Is...>)
{
    return {{ &f<Is>... }};
}

template <std::size_t N>
constexpr std::array<void(*)(/*..*/), N> make_funcs()
{
    return make_funcs(std::make_index_sequence<N>());
}

And then

int main() {
    std::cout << "Input dimension: ";
    uint x;
    std::cin >> x;
    if (x < max_dim) {
        constexpr auto funcs = make_funcs<max_dim>();
        funcs[x](/*..*/);
    } else {
        std::cout << "False Input.";
    }
}

CodePudding user response:

C 17 solution using a helper function, assuming that no return values are required from the Node<x> context:

#include<utility>

template<typename T, auto... I>
void f(std::integer_sequence<T, I...>, T x) {
    ((x == I && ([]{
        Node<I> node;
        // do something with node
    }(), true)) || ... || (std::cout << "False Input."));
}
    
// in main
f(std::make_integer_sequence<decltype(x), max_dim>{}, x);

It is possible to write a solution using only lambdas instead of a helper function, but it is going to look even less clear. The important concept here are fold expressions and the std::integer_sequence method of introducing template parameter packs into a function. The &&/||/(..., true) construction is essentially just an if/else if construct written as a single expression relying on short-circuiting behavior of the logical operators.

  • Related