Я хочу получить доступ к foo::func()
в лямбда-выражении, но класс foo
объявлен, но не определен на этом этапе. Есть ли способ для лямбда-выражения лениво?
Если я заменю лямбда-выражение эквивалентным функциональным объектом, то я могу это сделать.
Вот эквивалентный код:
Отдельный подход к объявлению и определению
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 ++.
Подход лямбда-выражений, который является моей целью
Я пытался исключить 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 ++ выдают ошибку «доступ к неполному типу 'foo'" в f.func();
. Если я добавлю void
возвращаемый тип, похоже, что g ++ лениво создает экземпляр тела лямбда-выражения. Однако clang ++ по-прежнему выдает ту же ошибку.
Результат:
- успех на g ++ 9.2.0
- ошибка в clang ++ 9.0.0
Какой компилятор допустим?
Если clang ++ допустим, есть лилюбой способ создания экземпляра тела лямбда-выражения, лениво похожий на эквивалентный struct 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 ++. Я ищу путь к тому же, используя лямбда-выражение, если это возможно.
Фон (Зачем мне это нужно?)
Я использую Boost (Candidate) SML,библиотека конечного автомата, основанная на метапрограммировании.
См. https://github.com/boost-experimental/sml/issues/93#issuecomment-283630876
struct with_prop
соответствует struct foo
. struct table
соответствует struct bar
. - Внешнее лямбда-выражение
[](with_prop& p) {...
соответствует void bar::memfun(foo& f)
. - Из-за разрешения перегрузки SML параметр
foo& f
не может быть auto& f
.
- Внутреннее лямбда-выражение
[](auto& p) -> void { ...
соответствует [](auto& f) -> void { ...
auto table::operator()() const noexcept
нельзя разделить на объявление и определение, поскольку SML использует тип возвращаемого значения до определения operator()()
.