I want to access foo::func()
in the lambda expression but the class foo
is declared but not defined at this point. Is there any way to lambda expression lazily ?
If I replace the lambda expression with the equivalent function object, then I can do that.
Here is the equivalent code:
Separate declaration and definition approach
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);
}
Running demo: https://wandbox.org/permlink/12xV6655DZXZxLqF
It can be compiled on both g++ and clang++.
Lambda expression approach that is my goal
I tried to eliminate struct lambda
.
Here is the code:
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);
}
The point is writing return type void
explicitly.
If I omit this, then the compiler both g++ and clang++ output error "ember access into incomplete type 'foo'" at f.func();
. If I add void
return type, it seems that g++ instantiate the body of the lambda expression lazily. However clang++ still outputs the same error.
Result:
- success on g++ 9.2.0
- error on clang++ 9.0.0
Which compiler is valid?
If clang++ is valid, is there any way to instantiate the body of the lambda expression lazily similar to the equivalent struct lambda
?
function object with member function template approach
I noticed that the Separate declaration and definition approach is not truly equivalent to the Lambda expression approach. The parameter of the lambda expression is auto&
but the parameter of lambda::operation()
of the Separate declaration and definition approach is foo&
.
It should be template. This is the equivalent code:
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);
}
Running Demo: https://wandbox.org/permlink/dJ1tqQE8dIMNZqgY
It doesn't require separate decralation of lambda::operator()
. And instantiate it lazily on both g++ and clang++. I'm looking for a way to the same thing using lambda expression if it is possible.
Background (Why do I need this?)
I'm using Boost (Candidate) SML, state machine library based on meta programming.
See https://github.com/boost-experimental/sml/issues/93#issuecomment-283630876
struct with_prop
is corresponding tostruct foo
.struct table
is corresponding tostruct bar
.- The outer lambda expression
[](with_prop& p) {...
is corresponding tovoid bar::memfun(foo& f)
.- Due to SML overload resolution, the parameter
foo& f
cannot beauto& f
.
- Due to SML overload resolution, the parameter
- The inner lambda expression
[](auto& p) -> void { ...
is corresponding to[](auto& f) -> void { ...
auto table::operator()() const noexcept
cannot separate to declaration and definition because SML uses the return type before theoperator()()
is defined.