【问题标题】:Bind to function with an unknown number of arguments in C++在 C++ 中绑定到具有未知数量参数的函数
【发布时间】:2014-11-25 14:51:06
【问题描述】:

假设我有一个std::function,它以T 类型的N 参数作为输入(这可以使用一些元编程魔法来构造;见下文),其中N 是一个模板参数强>。我想std::bind 第一个参数来构造一个带有N-1 参数的函数(例如myBind<...>(someValue))。我想不出一个聪明的元编程技巧来做到这一点。有什么建议吗?

来自Lambda function with number of arguments determined at compile-time

您可以编写带有嵌套typedef 类型的模板n_ary_function。这种类型可以如下使用:

template <int N> class A {
    typename n_ary_function<N, double>::type func;
};

遵循n_ary_function的定义:

template <std::size_t N, typename Type, typename ...Types>
struct n_ary_function {
    using type = typename n_ary_function<N - 1, Type, Type, Types...>::type;
};

template <typename Type, typename ...Types>
struct n_ary_function<0, Type, Types...> {
    using type = std::function<void(Types...)>;
};

【问题讨论】:

  • 你能发布你的代码来构建function吗?
  • @PiotrS.:我已将代码放入问题中。

标签: c++ c++11 metaprogramming template-meta-programming


【解决方案1】:

std::bind 使用std::is_placeholder 检测占位符,这意味着您可以通过部分特化std::is_placeholder 来编写自己的占位符以与std::bind 一起使用:

template<int N>
struct my_placeholder { static my_placeholder ph; };

template<int N>
my_placeholder<N> my_placeholder<N>::ph;

namespace std {
    template<int N>
    struct is_placeholder<::my_placeholder<N>> : std::integral_constant<int, N> { };
}

这使得从整数中获取占位符成为可能。剩下的就是标准的整数序列技巧:

template<class R, class T, class...Types, class U, int... indices>
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val, std::integer_sequence<int, indices...> /*seq*/) {
    return std::bind(f, val, my_placeholder<indices+1>::ph...);
}
template<class R, class T, class...Types, class U>
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val) {
    return bind_first(f, val, std::make_integer_sequence<int, sizeof...(Types)>());
}

Demostd::integer_sequence 在技术上是 C++14,但在 C++11 中很容易实现 - 只需搜索 SO。

【讨论】:

  • 谢谢。我已经有一个 C++11 的整数序列生成器,所以效果很好。我也删除了第 7-8 行(在演示中)。
【解决方案2】:
#include <functional>
#include <cstddef>
#include <utility>
#include <tuple>

template <std::size_t N, typename Type, typename... Types>
struct n_ary_function
{
    using type = typename n_ary_function<N - 1, Type, Type, Types...>::type;
};

template <typename Type, typename... Types>
struct n_ary_function<0, Type, Types...>
{
    using type = std::function<void(Types...)>;
};

using placeholders_list = std::tuple<decltype(std::placeholders::_1)
                                   , decltype(std::placeholders::_2)
                                   , decltype(std::placeholders::_3)
                                   , decltype(std::placeholders::_4)
                                   , decltype(std::placeholders::_5)
                                   , decltype(std::placeholders::_6)
                                   , decltype(std::placeholders::_7)
                                   , decltype(std::placeholders::_8)
                                   , decltype(std::placeholders::_9)
                                   , decltype(std::placeholders::_10)
                                   >;

template <typename F>
struct arity;

template <typename R, typename... Args>
struct arity<std::function<R(Args...)>>
{
    static constexpr std::size_t value = sizeof...(Args);
};

template <typename F, typename T, std::size_t... Ints>
auto binder(F f, T t, std::index_sequence<Ints...>)
{
    return std::bind(f, t,
           typename std::tuple_element<Ints, placeholders_list>::type{}...);
}

template <typename F, typename T>
auto myBind(F f, T t)
{
    return binder(f, t, std::make_index_sequence<arity<F>::value - 1>{});
}

测试:

#include <iostream>

void foo(int a, int b, int c, int d, int e)
{
    std::cout << a << b << c << d << e << std::endl;
}

int main()
{
    n_ary_function<5, int>::type f = foo;
    n_ary_function<4, int>::type b = myBind(f, 1);
    b(2, 3, 4, 5);
}

DEMO

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 2020-12-06
    • 2014-05-15
    相关资源
    最近更新 更多