为什么非捕获lambda不能默认构造,是否可以解决这个问题?

lef*_*out 5 c++ lambda templates c++11

可以使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

是否有其他方法来获得此功能,或者我是否必须将lambda旧式定义为命名类?

struct myFun {
  auto operator() (int x) -> int {return x*x;}
};
Run Code Online (Sandbox Code Playgroud)

(当然,我想使用的lambda函数并不那么简单x ? x²,所以只从几个标准函数类中选择就不够灵活了)

Ben*_*ley 5

您可以按照类似功能的例子make_pairmake_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;
}
Run Code Online (Sandbox Code Playgroud)


Naw*_*waz -2

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

我的解决方案只是本杰明答案的改进版本,您不必指定 lambda 参数type。所以不要这样写:

make_selfCompose<int>(f)(4); //Benjamin's solution
Run Code Online (Sandbox Code Playgroud)

你可以这样写:

make_selfCompose(f)(4); //improved - absence `int` template argument.
Run Code Online (Sandbox Code Playgroud)

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;
   };
};
Run Code Online (Sandbox Code Playgroud)

那么这里是一个改进版本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);
}
Run Code Online (Sandbox Code Playgroud)

这是测试程序:

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

查看在线演示

希望有帮助。:-)

  • “lambda 的类型不一定是一个类。” -- 错误,它需要是唯一的、未命名的非联合类类型(`§5.1.2/3`)。还需要重载`operator()`(相同的子句,p5)。 (6认同)
  • “事实上,标准要求无状态 lambda 可转换为函数指针。因此无状态 lambda 是功能上自由的函数,而不是类。” 完全不合逻辑。我不明白结论是如何得出的。正如 Xeo 指出的那样,现实恰恰相反:它“必须”是一个类类型。 (2认同)