5

可以使用 lambda 的类型作为模板参数,例如

template<typename InArg, typename Function>
class selfCompose {
  Function f;
 public:
  selfCompose(Function f): f(f) {}
  auto operator() (InArg x) -> decltype(f(f(x))) {
    return f(f(x));                              }
};

int main() {
  auto f = [](int x){return x*x;};
  std::cout << selfCompose<int, decltype(f)>(f)(4)  //  yields (4²)² = 256
            << std::endl;
  return 0;
}

但是,这种双重使用f有点多余。我们可以省略将 lambda 的类型作为模板传递(将其转换为合适的类型std::function(失去多态性 - 但 C++ lambda 无论如何都不是参数多态的)),但是我有一个应用程序,我更希望不必传递它的构造函数的(因为我想将我的类的初始化本身用作模板参数,其中需要特定的构造函数签名)。我希望它像

template<class InArg, class Function>
class selfCompose {
  Function f;
 public:
  selfCompose() {}  // default constructor for f
  auto operator() (InArg x) -> decltype(f(f(x))) {
    return f(f(x));                              }
};

int main() {
  auto f = [](int x){return x*x;};
  std::cout << selfCompose<int, decltype(f)>()(4) << std::endl;
  return 0;
}

但这不会编译,因为 lambdas 有一个已删除的默认构造函数。这对于捕获lambdas 来说当然是不可避免的,但是对于像我的示例中的简单的那些,这对我来说没有多大意义:它们不需要引用任何局部变量。

是否有其他方法可以获得此功能,或者我是否必须求助于将 lambda old-fashonly 定义为命名类?

struct myFun {
  auto operator() (int x) -> int {return x*x;}
};

(当然,我想使用的 lambda 函数并不那样简单x → x²,因此仅从几个标准函数类中选择不够灵活)

4

3 回答 3

5

您可以按照 和 等函数的示例进行make_pair操作make_shared

template<typename InArg, typename Function>
selfCompose<InArg, Function> make_selfCompose(Function f)
{
  return selfCompose<InArg, decltype(f)>(f);
}

int main() {
  auto f = [](int x){return x*x;};
  std::cout << make_selfCompose<int>(f)(4)
            << std::endl;
  return 0;
}
于 2012-11-16T15:57:26.127 回答
1

如果selfCompose是多态的,则无需显式传递参数类型或检查存储的仿函数类型。后者意味着它也将能够处理多态函子。

template<typename Functor>
struct self_compose_type {
    // Omitting encapsulation for brevity
    Functor functor;

    // It is possible to overload operator() to deal
    // with all cv and ref qualifiers combinations
    template<typename... T>
    auto operator()(T&&... t)
    // Don't use std::result_of for the return type
    -> decltype( std::declval<Functor&>()(std::declval<T>()...) )
    { return functor(std::forward<T>(t)...); }
};

template<typename Functor>
self_compose_type<Functor>
self_compose(Functor&& functor)
{ return { std::forward<Functor>(functor) }; }

// C++03 style:
template<typename Functor>
self_compose_type<typename std::decay<Functor>::type>
make_self_compose(Functor&& functor)
{ return { std::forward<Functor>(functor) }; }

没有必要制作operator()可变参数,如果您愿意,可以让它只接受一个参数。

于 2012-11-17T03:55:16.530 回答
-2

本杰明已经为您的案例发布了一个很好的解决方法。你可以用那个。

我的解决方案只是 Benjamin's answer 的改进版本,您不必指定 lambda parameter type。所以不要写这个:

make_selfCompose<int>(f)(4); //Benjamin's solution

你可以这样写:

make_selfCompose(f)(4); //improved - absence `int` template argument.

make_selfCompose推导出 lambda 参数类型本身。

对于此解决方案,让我们将第一function_traits类模板编写为:

#include <tuple>

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};

template <typename C, typename R, typename... A>
struct function_traits<R(C::*)(A...) const>
{
   template <size_t i>
   struct arg
   {
      typedef typename std::tuple_element<i, std::tuple<A...>>::type type;
   };
};

那么这里是一个改进的版本make_selfCompose

template<typename Fun> //<--- now it has one template parameter
selfCompose<typename function_traits<Fun>::template arg<0>::type, Fun>
make_selfCompose(Fun f)
{
  typedef typename function_traits<Fun>::template arg<0>::type InArg; //deduce it
  return selfCompose<InArg, decltype(f)>(f);
}

这是测试程序:

int main() {
  auto f = [](int x){return x*x;};
  std::cout << make_selfCompose(f)(4)  //notice the relief here!
            << std::endl;
  return 0;
}

查看在线演示

希望有帮助。:-)

于 2012-11-16T16:34:01.693 回答