【发布时间】:2019-10-05 06:55:46
【问题描述】:
我想在 lambda 表达式中访问 foo::func(),但此时已声明类 foo 但未定义。有什么办法可以懒惰地进行 lambda 表达式吗?
如果我将 lambda 表达式替换为等效的函数对象,那么我可以这样做。
这是等效的代码:
单独声明和定义方法
struct foo; // forward declaration
struct lambda {
void operator()(foo& f); // `lambda` only has declaration of `operator()`.
};
struct bar {
void memfun(foo& f) {
// Call `lambda` function object with the reference of incomplete `foo`.
lambda()(f);
}
};
struct foo { // Define foo
void func() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
// Define `lambda::operator()` after definition of `foo`.
inline void lambda::operator()(foo& f) {
f.func();
}
int main() {
foo f;
bar b;
b.memfun(f);
}
运行演示:https://wandbox.org/permlink/12xV6655DZXZxLqF
g++和clang++都可以编译。
我的目标是 Lambda 表达式方法
我试图消除struct lambda。
代码如下:
struct foo; // forward declaration
struct bar {
void memfun(foo& f) {
// Write explicit return type seems to instanciate
// lambda body lazily on g++
[](auto& f) -> void {
f.func();
}(f);
}
};
struct foo { // definition
void func() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main() {
foo f;
bar b;
b.memfun(f);
}
重点是明确写出返回类型void。
如果我省略了这一点,那么 g++ 和 clang++ 的编译器都会在 f.func(); 处输出错误“ember access into incomplete type 'foo'”。如果我添加 void 返回类型,似乎 g++ 会懒惰地实例化 lambda 表达式的主体。但是 clang++ 仍然输出相同的错误。
结果:
- g++ 9.2.0 成功
- clang++ 9.0.0 上的错误
哪个编译器有效?
如果 clang++ 是有效的,有没有办法像 struct lambda 一样懒惰地实例化 lambda 表达式的主体?
具有成员函数模板方法的函数对象
我注意到单独声明和定义方法并不真正等同于Lambda表达式方法。 lambda表达式的参数是auto&,而单独声明和定义方法的lambda::operation()的参数是foo&。
应该是模板。这是等效的代码:
struct foo; // forward declaration
struct lambda {
template <typename T>
void operator()(T& f) {
f.func();
}
};
struct bar {
void memfun(foo& f) {
lambda()(f);
}
};
struct foo { // definition
void func() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main() {
foo f;
bar b;
b.memfun(f);
}
运行演示:https://wandbox.org/permlink/dJ1tqQE8dIMNZqgY
它不需要单独声明lambda::operator()。并在 g++ 和 clang++ 上懒惰地实例化它。如果可能的话,我正在寻找一种使用 lambda 表达式的方法。
背景(我为什么需要这个?)
我正在使用 Boost (Candidate) SML,基于元编程的状态机库。
看 https://github.com/boost-experimental/sml/issues/93#issuecomment-283630876
-
struct with_prop对应struct foo。 -
struct table对应struct bar。 - 外部 lambda 表达式
[](with_prop& p) {...对应于void bar::memfun(foo& f)。- 由于 SML 重载解析,参数
foo& f不能为auto& f。
- 由于 SML 重载解析,参数
- 内部的lambda表达式
[](auto& p) -> void { ...对应[](auto& f) -> void { ... -
auto table::operator()() const noexcept不能与声明和定义分开,因为 SML 在定义operator()()之前使用返回类型。
【问题讨论】:
-
你能把中间的文本转换成 cmets 并将代码放在一起吗?这使minimal reproducible example 中的内容更加清晰。
-
你使用了一个不完整的结构体,它只是一个没有任何成员函数声明的声明。所以编译器此时不知道什么是
func,它是结构的成员函数。那么,为什么不在 structbar之前定义 structfoo呢?或者按照你第一次尝试定义 lambda 结构的方式定义结构foo? -
@user9335240,此代码关注编译器行为。原始问题是github.com/boost-experimental/sml/issues/…。 Boost.SML 需要
auto返回类型转换表。在此问题中,struct table由于 Boost.SML 要求而无法分离。 -
// Write explicit return type seems to instanciate lambda body lazily on g++“instanciate” 像“template instanciate”还是“struct instanciate”?每当实例化 lambda 结构时,恕我直言。 “制作”功能发生在编译时。因此,我发现“不完整的结构”是合理的。如果g++恰好编译了这个,它应该与Phase 7 or Phase 8 中是否发生事情有关。我想知道在这种情况下您是否可以指望g++s 的行为。 -
@TakatoshiKondo 你的代码看起来这个函数是
foo的半纯函数(不是闭包)(在问题中,它是with_prop),所以为什么不在这里使用函数指针??typedef void (*lambda_type) (struct foo &);然后声明一个extern const,然后在foo声明之后将其声明为一个lambda。 wandbox.org/permlink/6EhybAMZjfMgZ2v5
标签: c++ lambda c++14 lazy-evaluation generic-lambda