【问题标题】:Template function binding variadic number of tuple's elements to another function as arguments模板函数将元组元素的可变数量绑定到另一个函数作为参数
【发布时间】:2016-01-12 13:19:46
【问题描述】:

在 c++11/14 中有没有办法像这样编写可变参数模板函数:

template <typename ReturnType, typename Args...>
std::function<ReturnType()> bindArgumentsFromTuple
                                  (std::function<ReturnType(Args... args)> f,
                                  const std::tuple<Args...>& t)

将元组t的元素作为参数绑定到函数f(使得函数参数和元组中元素的数量及其类型相同)?

使用示例:

void dummy_print(int i, double d)
{
    std::cout << i << "," << d << '\n';
}
void dummy_print2(int i, double d, std::string& s)
{
    std::cout << i << "," << d <<  "," << s << '\n';
}

int main() {
    std::tuple<int,double> t(77,1.1);
    std::tuple<int,double,std::string> t2(1,2.0,"aaa");
    auto f1 = bindArgumentsFromTuple(dummy_print, t);
    f1();
    auto f2 = bindArgumentsFromTuple(dummy_print2, t2);
    f2();

    return 0;
}

【问题讨论】:

    标签: c++ c++11 tuples c++14 variadic-templates


    【解决方案1】:
    template <typename F, typename T, std::size_t... indices>
    auto bindTuple(F&& f, T&& t, std::index_sequence<indices...>) {
        return std::bind(std::forward<F>(f), std::get<indices>(std::forward<T>(t))...);
    }
    
    template <typename F, typename T>
    auto bindTuple(F&& f, T&& t) {
        return bindTuple(std::forward<F>(f), std::forward<T>(t),
                       std::make_index_sequence<std::tuple_size<std::decay_t<T>>{}>{});
    }
    

    以上将支持任何元组式,即std::arraystd::tuple 等,同时涉及占位符参数。 Demo.

    【讨论】:

    • 谢谢!这是我在 C++ 中的另一个知识差距:std::index_sequence :)
    • 在第一次重载中,您不会多次转发t(可能会移动它)吗?
    • @0x499602D2 我正在转发它,所以std::get 可以相应地转发元组的元素,尽可能避免复制
    • STL 通常会警告 bind 做一些可能需要也可能不需要的额外魔法。
    • @T.C.你的意思是INVOKE
    【解决方案2】:

    使用std::index_sequence,您可以执行以下操作:

    template <typename ReturnType, typename ...Args, std::size_t ... Is>
    std::function<ReturnType()>
    bindArgumentsFromTuple_impl(std::function<ReturnType(Args...)> f,
                           const std::tuple<Args...>& t, std::index_sequence<Is...>)
    {
        return [=]() { return f(std::get<Is>(t)...);};
    }
    
    template <typename ReturnType, typename ...Args>
    std::function<ReturnType()>
    bindArgumentsFromTuple(std::function<ReturnType(Args...)> f,
                           const std::tuple<Args...>& t)
    {
        return bindArgumentsFromTuple_impl(f, t, std::index_sequence_for<Args...>{});
    }
    

    Live Demo

    【讨论】:

    • std::function?认真的吗?
    • 我保留了 OP 的签名,但你是对的,你的方式更好。
    • OP 接受带有非常量引用的strings;我怀疑他知道什么对他最好:-)
    • 谢谢!当我写信给@Colombo 时,这是我在 C++ 中的另一个知识空白:std::index_sequence :)
    • @attuda:你不能接受多个答案,但你可以投票多个​​答案。
    猜你喜欢
    • 1970-01-01
    • 2017-07-11
    • 2023-03-16
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多