按类型实例化C++ lambda
Instantiating C++ lambda by its type
我想要一种从函数制作函子的方法。现在我尝试通过 lambda 函数包装函数调用并在以后实例化它。但是编译器说比lambda构造函数被删除。那么有没有办法编译这段代码呢?或者也许另一种方式?
#include <iostream>
void func()
{
std::cout << "Hello";
}
auto t = []{ func(); };
typedef decltype(t) functor_type;
template <class F>
void functor_caller()
{
F f;
f();
}
int main()
{
functor_caller<functor_type>();
return 0;
}
现在我收到这样的编译器错误:
error: use of deleted function '<lambda()>::<lambda>()'
error: a lambda closure type has a deleted default constructor
在我看来,唯一的方法是使用宏:
#define WRAP_FUNC(f)
struct f##_functor
{
template <class... Args >
auto operator()(Args ... args) ->decltype(f(args...))
{
return f(args...);
}
};
然后
WRAP_FUNC(func);
然后(主要)
functor_caller<func_functor>()
代码没有意义。想象一下,你有一个像这样的捕获 lambda:
{
int n = 0;
auto t = [&n](int a) -> int { return n += a; };
}
默认构造一个 decltype(t)
类型的对象可能意味着什么?
正如@Matthieu所建议的,您可以将 lambda 包装到一个function
对象中:
std::function<int(int)> F = t;
或者,您可以直接在 lambda(或任何可调用实体)的类型上模板化调用站点:
template <typename F>
int compute(int a, int b, F f)
{
return a * f(b); // example
}
用法:int a = 0; for (int i : { 1, 3, 5 }) { a += compute(10, i, t); }
如果可能的话,第二种样式更可取,因为转换为std::function
是一个不平凡的、可能代价高昂的操作,通过结果对象进行的实际函数调用也是如此。但是,如果您需要存储异构可调用实体的统一集合,那么std::function
很可能是最简单、最方便的解决方案。
Lambda 没有默认构造函数。 曾。 他们有时授予访问权限的唯一构造函数是(取决于他们捕获的内容)复制和/或移动构造函数。
如果创建没有公共默认构造函数的函子,则会收到相同的错误。
在 C++17 中,您可以使用 lambda constexpr
并operator+
衰减到函数指针来解决这个问题。 携带函数指针并调用函数指针的类型很容易使用auto
模板参数。
在C++11中,你必须变得有点笨拙。
template<class F>
struct stateless_lambda_t {
static std::aligned_storage_t< sizeof(F), alignof(F) >& data() {
static std::aligned_storage_t< sizeof(F), alignof(F) > retval;
return retval;
};
template<class Fin,
std::enable_if_t< !std::is_same< std::decay_t<Fin>, stateless_lambda_t >{}, int> =0
>
stateless_lambda_t( Fin&& f ) {
new ((void*)&data()) F( std::forward<Fin>(f) );
}
stateless_lambda_t(stateless_lambda_t const&)=default;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return (*static_cast<F*>( (void*)&data() ))(std::forward<Args>(args)...);
}
stateless_lambda_t() = default;
};
template<class F>
stateless_lambda_t<std::decay_t<F>> make_stateless( F&& fin ) {
return {std::forward<F>(fin)};
}
现在我们可以:
auto t = make_stateless([]{ func(); });
你的代码有效。
static_assert
或 SFINAE 表示F
实际上是空类型可能是个好主意。 你知道,为了质量。
C++14 功能的使用可以用手动decltype
和喷出typename
和::type
关键字代替。 这个答案最初是为一个C++14的问题而写的,这个问题被关闭为这个问题的答案的副本。
活生生的例子。
我们可以假设 lambda 将始终为空,因此,我们可以从另一个空类型进行强制转换,因为它们都具有相同的内存布局。因此,我们构建了一个包装类,该类使默认的可构造函数对象:
template<class F>
struct wrapper
{
static_assert(std::is_empty<F>(), "Lambdas must be empty");
template<class... Ts>
auto operator()(Ts&&... xs) const -> decltype(reinterpret_cast<const F&>(*this)(std::forward<Ts>(xs)...))
{
return reinterpret_cast<const F&>(*this)(std::forward<Ts>(xs)...);
}
};
现在添加一个静态断言以确保 lambda 始终为空。这种情况应该始终如此(因为它需要衰减到函数指针),但标准没有明确保证这一点。所以我们使用断言至少来捕捉 lambda 的疯狂实现。然后我们只是将包装类强制转换为 lambda,因为它们都是空的。
最后,lambda 可以像这样构造:
template <class F>
void function_caller()
{
wrapper<F> f;
f();
}
No.
但是我相信 lambda 可以复制,因此您的functor_caller
可以采用参数来初始化其属性。
不过,与其重新发明轮子,我会用std::function
来代替。
在 C++20 之前,闭包类型不是默认可构造的,也没有默认构造函数。
由于 C++20 个无捕获的 lambda 是默认可构造的,即它们具有默认构造函数。
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 可组合的lambda/std::函数与std::可选
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 如何将lambda作为模板类的成员函数参数
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- 在 lambda 捕获中声明的变量的类型推导
- 我可以将调用类的"this"传递给 lambda 函数吗?
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- 模板函数指针和lambda
- 两组使用lambda函数的大括号
- 使lambda不可复制/不可移动
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- 将带有unique_ptr的可变 lambda 传递给 const&std::function
- AWS Lambda C++运行时权限被拒绝
- 捕获lambda中的std::数组
- 这 4 个 lambda 表达式之间有什么区别?
- 在实现文件中使用头文件的通用 lambda
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?