【问题标题】:Feed template function element from tuple at runtime?在运行时从元组中提供模板函数元素?
【发布时间】:2015-01-06 00:03:31
【问题描述】:

在 C++ 中,我有一个包含一些元素的元组:

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

还有一些模板函数可以完美地处理整数和字符:

template <class T> void my_function(T);

现在,假设在运行时我想在我的元组的一个元素上运行 my_function(但我不知道是哪个)。我注意到无法执行以下操作:

unsigned int n;

// Give a value to n

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

但是,原则上我需要的应该与以下内容相同:

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
}

所以在我看来这应该是可行的.. 是吗?

【问题讨论】:

  • std::get 返回第 n 个类型的元组元素,无论它是什么,它都应该被带到模板函数中,所以它看起来应该是可能的。你试过了吗?不行吗?
  • 我尝试做类似unsigned int n; cin&gt;&gt;n; my_function(std::get &lt;n&gt; (my_tuple)) 的操作,但我得到`没有匹配的函数可供调用

标签: c++ runtime tuples


【解决方案1】:

n 是运行时值,它不能用于在编译时实例化模板。您的 switch 有效,因为您手动实例化每个 std::get&lt;N&gt;,并将它们连接到相应的运行时值。

但是,是的,写那个死脑筋的switch 树有点麻烦。为什么不让编译器生成带有一点 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】:

    以下可能会有所帮助:

    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

    【讨论】:

    • 哈哈,我一开始是这样的,但我不喜欢类型擦除。
    猜你喜欢
    • 2011-07-04
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 2015-05-31
    相关资源
    最近更新 更多