Feed template function element from tuple at runtime?

别说谁变了你拦得住时间么 提交于 2019-12-01 22:55:50

问题


In C++ I have a tuple with some elements in it:

std::tuple <int, char> my_tuple(3, 'q');

And some template function that perfectly works both on integers and chars:

template <class T> void my_function(T);

Now, say that at runtime I want to run my_function on one of the elements of my tuple (but I don't know which). I noticed that it is not possible to do something like:

unsigned int n;

// Give a value to n

my_function(std::get <n> (my_tuple));

However, in principle what I need should be identical to something like:

unsigned int n;

// Give a value to n

switch(n)
{
    case 0:
      my_function(std::get <0> (my_tuple));
      break;
    case 1:
      my_function(std::get <1> (my_tuple));
      break;
    default:
      // Do nothing or throw an exception
}

So it sounds to me like this should be feasible.. is it?


回答1:


n being a runtime value, it can't be used to instanciate a template at compile-time. Your switch works because you manually instanciate each std::get<N>, and wire them to the corresponding runtime value.

But yeah, it's a bit of a chore to write that braindead switch tree. Why not let the compiler generate the boilerplate with a bit of TMP ?

#include <tuple>
#include <cassert>
#include <iostream>

template <class T>
void my_function(T);

// Test specialisations to see what's going on
template <> void my_function(int i) { std::cout << "int " << i << '\n'; }
template <> void my_function(char c) { std::cout << "char " << c << '\n'; }

namespace detail {
    // Available in std in C++14
    template <bool P, class T>
    using enable_if_t = typename std::enable_if<P, T>::type;

    // Mockup function signature to pick up the call when enable_if shunts
    template <std::size_t N, class T = void>
    void callMyFunc(T&&, ...) {
        assert(!"Index not in range !");
    }

    // "Simple" recursive solution, removes itself from the overload set
    // to stop recursion
    template <std::size_t N, class... Ts,
        class = enable_if_t<N < sizeof...(Ts), void>>
    void callMyFunc(std::tuple<Ts...> &tuple, std::size_t n) {
        return n == N
            ? my_function(std::get<N>(tuple))
            : callMyFunc<N + 1>(tuple, n);
    }
}

// Tiny user-friendly wrapper
template <class... Ts>
void callMyFunc(std::tuple<Ts...> &tuple, std::size_t n) {
    detail::callMyFunc<0u>(tuple, n);
}

int main(int, char**) {
    std::tuple <int, char> my_tuple(3, 'q');

    // Success.
    callMyFunc(my_tuple, 0u);
    callMyFunc(my_tuple, 1u);

    return 0;
}



回答2:


Following may help:

template <typename T> struct caller;

template <typename... Ts> struct caller<std::tuple<Ts...>>
{
    template <typename F>
    void operator() (F f, std::tuple<Ts...>& t, int n)
    {
        (*this)(f, t, n, std::index_sequence_for<Ts...>());
    }
private:
    template <typename F, std::size_t ... Is>
    void operator() (F f, std::tuple<Ts...>& t, int n, std::index_sequence<Is...>)
    {
        std::function<void(F, std::tuple<Ts...>&)> fs[] = { &helper<F, Is>... };
        fs[n](f, t);
    }

    template <typename F, std::size_t I>
    static void helper(F f, std::tuple<Ts...>& t)
    {
        f(std::get<I>(t));
    }

};

template <typename F, typename T>
void call(F f, T& t, int n)
{
    caller<T>()(f, t, n);
}

Live example



来源:https://stackoverflow.com/questions/27790038/feed-template-function-element-from-tuple-at-runtime

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!