简体   繁体   English

是否可以从函数模板返回可变参数lambda?

[英]Is it possible to return a variadic lambda from a function template?

I have the following piece of code (c++11): 我有以下代码(c ++ 11):

template <typename F,
          typename FirstT,
          typename... FIn>
auto min_on(F f, FirstT first, FIn... v) -> typename std::common_type<FirstT, FIn...>::type
{
  using rettype = typename std::common_type<FirstT, FIn...>::type;
  using f_rettype = decltype(f(first));

  rettype result = first;
  f_rettype result_trans = f(first);
  f_rettype v_trans;
  (void)std::initializer_list<int>{
      ((v_trans = f(v), v_trans < result_trans)
           ? (result = static_cast<rettype>(v), result_trans = v_trans, 0)
           : 0)...};
  return result;
}

Which basically returns the argument result that produced the minimum value for expression f(result) . 这基本上返回产生表达式f(result)的最小值的参数result This can be called like this: 这可以像这样调用:

auto mod7 = [](int x)
{
    return x % 7;
};

auto minimum = min_on(mod7, 2, 8, 17, 5);
assert( minimum == 8); // since 8%7 = 1 -> minimum value for all arguments passed

Now I would like to use this in a 'curried' way so that I can get a variadic lambda from min_on and then call it with arguments (that I might receive later), like so: 现在我想以'curried'的方式使用它,这样我就可以从min_on获得一个可变的lambda,然后用参数调用它(我可能会稍后收到),如下所示:

auto mod7 = [](int x)
{
    return x % 7;
};

auto f_min = min_on(mod7);
auto minimum = f_min(2, 8, 17, 5);
// or 
auto minimum = min_on(mod7)(2, 8, 17, 5);

Is this even possible? 这甚至可能吗?

In C++11, the following works if you're willing to manually create the function object: 在C ++ 11中,如果您愿意手动创建函数对象,则以下内容有效:

template <typename F>
struct min_on_t {
    min_on_t(F f) : f(f) {}

    template <typename T, typename... Ts>
    auto operator ()(T x, Ts... xs) -> typename std::common_type<T, Ts...>::type
    {
        // Magic happens here.
        return f(x);
    }

    private: F f;
};

template <typename F>
auto min_on(F f) -> min_on_t<F>
{
    return min_on_t<F>{f};
}

And then call it: 然后叫它:

auto minimum = min_on(mod7)(2, 8, 17, 5);

To use lambdas in C++14, you need to omit the trailing return type because you cannot specify the type of the lambda without assigning it to a variable first, because a lambda expression cannot occur in an unevaluated context . 要在C ++ 14中使用lambdas,您需要省略尾随返回类型,因为您不能首先指定lambda的类型而不将其分配给变量,因为lambda表达式不能在未评估的上下文中出现

template <typename F>
auto min_on(F f)
{
    return [f](auto x, auto... xs) {
        using rettype = std::common_type_t<decltype(x), decltype(xs)...>;
        using f_rettype = decltype(f(x));

        rettype result = x;
        f_rettype result_trans = f(x);
        (void)std::initializer_list<int>{
          (f(xs) < result_trans
               ? (result = static_cast<rettype>(xs), result_trans = f(xs), 0)
               : 0)...};
        return result;
    };
}

Not sure on C++11, but in C++14, you could create a lambda to wrap your function in: 在C ++ 11上不确定,但在C ++ 14中,你可以创建一个lambda来包装你的函数:

auto min_on_t = [](auto f) {
    return [=](auto ... params) {
        return min_on(f, params...);
    };
};

auto min_t = min_on_t(mod7);
auto minimum = min_t(2, 8, 17, 5);

Live on Coliru 住在Coliru

In C++14 this is easy. 在C ++ 14中,这很容易。

template<class F>
auto min_on( F&& f ) {
  return [f=std::forward<F>(f)](auto&& arg0, auto&&...args) {
    // call your function here, using decltype(args)(args) to perfect forward
  };
}

Many compilers got auto return type deduction and arguments in lambdas working prior to full C++14 support. 许多编译器在完全支持C ++ 14之前在lambda中得到了auto返回类型推导和参数。 So a nominal C++11 compiler might be able to compile this: 所以标称的C ++ 11编译器可能能够编译它:

auto min_on = [](auto&& f) {
  return [f=decltype(f)(f)](auto&& arg0, auto&&...args) {
    // call your function here, using decltype(args)(args) to perfect forward
  };
}

in C++11: 在C ++ 11中:

struct min_on_helper {
  template<class...Args>
  auto operator()(Args&&...args)
  -> decltype( min_on_impl(std::declval<Args>()...) )
  {
    return min_on_impl(std::forward<Args>(args)...);
  }
};

is boilerplate. 是样板。 This lets us pass the entire overload set of min_on_impl around as one object. 这让我们将min_on_impl的整个重载集作为一个对象传递。

template<class F, class T>
struct bind_1st_t {
  F f;
  T t;
  template<class...Args>
  typename std::result_of<F&(T&, Args...)>::type operator()(Args&&...args)&{
    return f( t, std::forward<Args>(args)... );
  }
  template<class...Args>
  typename std::result_of<F const&(T const&, Args...)>::type operator()(Args&&...args)const&{
    return f( t, std::forward<Args>(args)... );
  }
  template<class...Args>
  typename std::result_of<F(T, Args...)>::type operator()(Args&&...args)&&{
    return std::move(f)( std::move(t), std::forward<Args>(args)... );
  }
};
template<class F, class T>
bind_1st_t< typename std::decay<F>::type, typename std::decay<T>::type >
bind_1st( F&& f, T&& t ) {
  return {std::forward<F>(f), std::forward<T>(t)};
}

gives us bind_1st . 给我们bind_1st

template<class T>
auto min_on( T&& t )
-> decltype( bind_1st( min_on_helper{}, std::declval<T>() ) )
{
  return bind_1st(min_on_helper{}, std::forward<T>(t));
}

is modular and solves your problem: both min_on_helper and bind_1st can be tested independently. 是模块化的并且解决了您的问题: min_on_helperbind_1st都可以独立测试。

You can also replace bind_1st with a call to std::bind , but in my experience the quirks of std::bind make me extremely cautious about recommending that to anyone. 你也可以用std::bind来调用bind_1st ,但根据我的经验, std::bind的怪癖让我非常谨慎地推荐给任何人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否可以展开可变参数(lambda)模板并将这些函数的返回值传递给另一个可变参数函数? - Is it possible to unfold a variadic (lambda) template and the pass those functions return value to another variadic function? 变体模板函数接受lambda - Variadic template function accepting lambda 在variadic模板中从lambda隐式转换为std :: function - implicit convert from lambda to std::function inside variadic template 将std :: function与lambda和variadic模板一起使用 - Use std::function with lambda and variadic template Variadic lambda vs variadic template function:严格等效? - Variadic lambda vs variadic template function : stricly equivalent? 使用可变参数lambda迭代可变参数函数模板的参数 - Iterating through parameters of a variadic function template using variadic lambda 将“传递”函数模板作为generic-variadic lambda return语句的好方法是什么? - Is it good approach to “pass” function template as generic-variadic lambda return statement? 如何从可变参数模板类的lambda中使用可变参数 - How to use variadic parameter in lambda from variadic template class 如何从通用模板<typename T>中提取lambda的Return Type和Variadic Parameters Pack - How to extract lambda's Return Type and Variadic Parameters Pack back from general template<typename T> 是否可以在可变参数模板函数中扩展非可变参数? - Is it possible to expand non-variadic arguments in a variadic template function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM