c++ - 在 C++ 中使用函数嵌套无捕获 lambda?

标签 c++ lambda constexpr stateless

问题

在 C++ 中传递无捕获 lambda 表达式时是否可以嵌套它们?

据我所知,情况似乎并非如此;相反,似乎您必须创建一个模板类,并定义静态函数,然后传递它们。

背景

与这篇文章相关,对于pybind11:Possible to have logical operations (e.g. `ndarray.__eq__`) not return `bool` in NumPy?

基本上,我想看看是否可以避免宏并仍然提供与 Numpy UFunc API 一起使用的无状态函数(没有任何类型删除的 void* data 恶作剧)。

我的目标是无状态,因为 API 似乎有一些可以包含 void* 数据的函数,我可以用它来传递另一个函数指针(或通过捕获删除 lambda),但其中一些似乎并非如此。

盲目黑客

这是我的黑客攻击:

// Goal: Wrap a function of type `Func` without capture.
typedef void (*Func)();


// NOPE: `b` ain't stateless.
Func wrap(Func a) {
  return [a]() { a(); };
}
int main() {
  Func a = []() { cout << "A1\n"; };
  wrap(a)();
}


// KINDA: Compiles, but `a` wasn't a parameter :(
// - Could use arrays a constexpr indices to fake it :( * 2
int main() {
  static const Func a = []() { cout << "A1\n"; };
  Func b = []() { a(); };
  b();
}

// YUP-ish: Works, cannot deal with lambdas :(
template <Func a>
Func wrap() {
  return []() { a(); };
}
// - Cannot be in a class in function scope :(
void a2() { cout << "A2\n"; }
int main() {
  Func b = wrap<tmp::a2>();
  b();
}

// NOPE: Lambda doesn't have default constructor (but what else would it do???)
int main() {
  auto a = []() { cout << "A3\n"; };
  using A = decltype(a);
  Func b = []() { A a{}; a(); };
  b();
}

我看到 constexpr lambda 引入了一些新内容,但这似乎更多的是关于返回值 constexpr,而不是 lambda 本身的定义(这样它就可以作为模板参数或其他参数传递)。

最佳答案

您可以将 lambda 复制到静态变量中:

template<typename F>
auto wrap(F a) {
    static auto F b = std::move(a);
    return []() { b(); };
}

每个 lambda 都有不同的类型,因此对于每个 lambda,都会创建一个新的静态变量,因为该函数是模板化的。

请注意,仅当传递的可调用对象具有不同类型时它才有效。如果你只使用无状态函数对象,就不会有任何问题。

作为安全保障,您还可以确保仅发送无捕获的 lambda:

template<typename F, std::void_t<
    decltype(+std::declval<F>()),
    decltype(&F::operator())
>* = nullptr>
auto wrap(F a) {
    static auto F b = std::move(a);
    return []() { b(); };
}

sfinae 表达式使用 catpureless lambda 查找一元 operator+,并且还会查找 lambda 中是否存在 operator() 成员。

关于c++ - 在 C++ 中使用函数嵌套无捕获 lambda?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49205779/

相关文章:

c++ - 创建对话树

用于 int 范围的 Java 8 IntStream?

c++ - 在编译时初始化 c++ std::bitset

c++ - 对静态 constexpr char[] 的 undefined reference

c++ - 为什么 constexpr 假设我的方法是 const?

c++ - 将 Boost 序列化与 xml_oarchive 一起使用时 assertion_failed

C++:简单递归搜索函数的运行时错误

c++ - 如何使用静态数组释放内存?

java - 为什么 Java 编译器不能从约束 Iterable< 中推断出 Iterable<String>?扩展 CharSequence> 和 () -> (Iterator<String>)

c++ - 如何确定 std::function 的参数数量?