如何在c ++ 11中转换忽略参数的函数?

Erd*_*mus 4 lambda bind function c++11

我正在寻找一个更优雅的代码来忽略不必要的参数.有点逆转std :: bind.

void doSomething(function<A(B)> callback); // Given function

// Instead of
void myDoSomething(function<A()> callback0) {
   doSomething([&](B b) { 
                  return callback0();
              });
}

// I want
void myDoSomething(function<A()> callback0) {
   doSomething(add_ignored_arg<B>(callback0));
}
Run Code Online (Sandbox Code Playgroud)

Pio*_*cki 6

选项1

C++ 11基本解决方案,将一个被忽略的参数注入第一个位置(DEMO 1):

template <typename Arg, typename R, typename... Args>
std::function<R(Arg, Args...)> add_ignored_arg(std::function<R(Args...)> f)
{
    return [f] (Arg&& /*arg*/, Args&&... args) { return f(std::forward<Args>(args)...); };
}
Run Code Online (Sandbox Code Playgroud)

注意: std::forward<Args>(args)正常工作(尽管Args&&这里不是转发引用),因为std::function将值传递的参数转换为rvalue引用,而lvalue引用根据规则折叠:& &&- > &.

选项#2

带有通用lambda的C++ 14基本解决方案,首先将一个被忽略的参数注入(DEMO 2):

template <typename Arg, typename R, typename... Args>
std::function<R(Arg, Args...)> add_ignored_arg(std::function<R(Args...)> f)
{
    return [f] (auto&& /*arg*/, auto&&... args) { return f(std::forward<decltype(args)>(args)...); };
}
Run Code Online (Sandbox Code Playgroud)

选项#3

C++ 11高级解决方案,将忽略的参数注入任何地方,附加的重载接受原始函数指针std::function包装器(DEMO 3):

template <std::size_t N, typename Arg, typename R, typename... Args, std::size_t... Before, std::size_t... After, typename Tuple = std::tuple<Args...>>
auto inject_param(index_sequence<Before...>, index_sequence<After...>)
    -> std::function<R(typename std::tuple_element<Before, Tuple>::type..., Arg, typename std::tuple_element<N + After, Tuple>::type...)>;

template <std::size_t N, typename Arg, typename R, typename... Args, std::size_t... Before, std::size_t... After, typename Tuple = std::tuple<Args...>>
auto add_ignored_arg(std::function<R(Args...)> f, index_sequence<Before...>, index_sequence<After...>)
    -> decltype(inject_param<N, Arg, R, Args...>(index_sequence<Before...>{}, index_sequence<After...>{}))
{
    return [f] (typename std::tuple_element<Before, Tuple>::type&&... before
                , Arg&& /*arg*/
                , typename std::tuple_element<N + After, Tuple>::type&&... after)
                {
                    return f(std::forward<typename std::tuple_element<Before, Tuple>::type>(before)...,
                             std::forward<typename std::tuple_element<N + After, Tuple>::type>(after)...);
                };
}

template <std::size_t N, typename Arg, typename R, typename... Args, typename Tuple = std::tuple<Args...>>
auto add_ignored_arg(std::function<R(Args...)> f)
    -> decltype(inject_param<N, Arg, R, Args...>(make_index_sequence<N>{}, make_index_sequence<sizeof...(Args) - N>{}))
{
    return add_ignored_arg<N, Arg>(f, make_index_sequence<N>{}, make_index_sequence<sizeof...(Args) - N>{});
}

template <std::size_t N, typename Arg, typename R, typename... Args, typename Tuple = std::tuple<Args...>>
auto add_ignored_arg(R(*f)(Args...))
    -> decltype(inject_param<N, Arg, R, Args...>(make_index_sequence<N>{}, make_index_sequence<sizeof...(Args) - N>{}))
{
    return add_ignored_arg<N, Arg>(std::function<R(Args...)>(f), make_index_sequence<N>{}, make_index_sequence<sizeof...(Args) - N>{});
}
Run Code Online (Sandbox Code Playgroud)

注意:执行index_sequence是在demo中.转发按照选项#1中的描述进行.

选项#4

C++ 14高级解决方案,使用通用lambda和返回类型推导(DEMO 4)将忽略的参数注入任何地方:

template <std::size_t N, typename Arg, typename R, typename... Args, std::size_t... Before, std::size_t... After, typename Tuple = std::tuple<Args...>>
auto add_ignored_arg(std::function<R(Args...)> f, std::index_sequence<Before...>, std::index_sequence<After...>)
    -> std::function<R(typename std::tuple_element<Before, Tuple>::type..., Arg, typename std::tuple_element<N + After, Tuple>::type...)>
{
    return [f] (auto&&... args)
                {
                    auto t = std::forward_as_tuple(std::forward<decltype(args)>(args)...);
                    return f(static_cast<typename std::tuple_element<Before, decltype(t)>::type>(std::get<Before>(t))...,
                             static_cast<typename std::tuple_element<N + After + 1, decltype(t)>::type>(std::get<N + After + 1>(t))...);
                };
}

template <std::size_t N, typename Arg, typename R, typename... Args, typename Tuple = std::tuple<Args...>>
auto add_ignored_arg(std::function<R(Args...)> f)
{
    return add_ignored_arg<N, Arg>(f, std::make_index_sequence<N>{}, std::make_index_sequence<sizeof...(Args) - N>{});
}

template <std::size_t N, typename Arg, typename R, typename... Args, typename Tuple = std::tuple<Args...>>
auto add_ignored_arg(R(*f)(Args...))
{
    return add_ignored_arg<N, Arg>(std::function<R(Args...)>(f), std::make_index_sequence<N>{}, std::make_index_sequence<sizeof...(Args) - N>{});
}
Run Code Online (Sandbox Code Playgroud)

测试

struct B {};

void foo(int i, char c, double d)
{
    std::cout << i << " " << c << " " << d << std::endl;
}

void doSomething(std::function<void(int, char, B, double)> callback)
{
    callback(123, 'A', B{}, 3.14f);
}

void myDoSomething(std::function<void(int, char, double)> callback)
{
    doSomething(add_ignored_arg<2, B>(callback));
}

int main()
{
    myDoSomething(&foo);
}
Run Code Online (Sandbox Code Playgroud)

输出:

123 A 3.14
Run Code Online (Sandbox Code Playgroud)

完整的C++ 11演示

完整的C++ 14演示