我想一个方法,使仿函数的功能。 现在,我试图通过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>()
该代码是没有意义的。 想象一下,你有这样的捕获的λ:
{
int n = 0;
auto t = [&n](int a) -> int { return n += a; };
}
还有什么比这可能意味着以缺省方式构造类型的对象decltype(t)
?
作为@Matthieu建议,你可以换拉姆达成function
对象:
std::function<int(int)> F = t;
或者你可以在拉姆达(或任何可调用实体)的直接类型的模板调用点:
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); }
int a = 0; for (int i : { 1, 3, 5 }) { a += compute(10, i, t); }
如果可能的话,第二样式是优选的,因为转换到std::function
是不平凡的,可能昂贵的操作中,当通过所得到的物体的实际的函数调用。 但是,如果你需要存储的异构可调用实体的统一收集,然后std::function
可能是最简单,最方便的解决方案。
Lambda表达式没有默认构造函数。 永远。 唯一的建设者,他们有时会给访问时(取决于它们捕获的)复制和/或移动的构造。
如果你创建没有公共默认构造函数对象,你会得到同样的错误。
在C ++ 17可以用解决这个constexpr
拉姆达和operator+
衰减到函数指针。 携带一个函数指针,并调用它A型很容易用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的问题。
活生生的例子 。
我们可以假设,拉姆达永远是空的,因此,我们可以做一个演员是另一个空类型,因为它们都具有相同的内存布局。 因此,我们建立了一个包装类,使一个缺省构造函数对象:
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表达式。 然后,我们只投了包装类的拉姆达,因为他们两人都是空的。
最后,拉姆达可以构造是这样的:
template <class F>
void function_caller()
{
wrapper<F> f;
f();
}
没有。
不过我相信,lambda表达式可以被复制,所以你functor_caller
可以带参数初始化其属性。
尽管如此,而不是重新发明轮子,我会使用std::function
来代替。