考虑下面的代码:
struct LambdaWrapper {
auto getLambda() {
return []() {
std::cout << "Lambda is called" << std::endl;
};
}
};
void useLambda(auto &&lambda) {
lambda();
}
int main() {
LambdaWrapper w;
useLambda(w.getLambda());
return 0;
}
我将
auto
用于 LambdaWrapper::getLambda()
返回类型和 useLambda()
函数的参数。但实际上在这段代码中使用了唯一的类型,这就是 LambdaWrapper::getLambda()
返回的内容,所以我可以为该类型定义一个别名:
struct LambdaWrapper {
auto getLambda() { ... }
static LambdaWrapper* get();
};
using LambdaType = decltype(LambdaWrapper::get()->getLambda());
void useLambda(const LambdaType &lambda);
现在我希望使这个别名成为
LambdaWrapper
类的一部分:
struct LambdaWrapper {
auto getLambda() { ... }
static LambdaWrapper* get();
using LambdaType = decltype(LambdaWrapper::get()->getLambda());
};
void useLambda(const LambdaWrapper::LambdaType &lambda);
但现在我明白了
错误:在扣除“auto”之前使用“auto LambdaWrapper::getLambda()”
我如何在类中定义这个别名?
问题在于类是分两遍解析的。在第一遍中,编译器会看到声明
auto getLambda()
(不是定义)和 using LambdaType = decltype(LambdaWrapper::get()->getLambda());
,但是,由于尚无 getLamba
的定义可用,因此解析失败。这就是为什么编译器在推断返回类型之前告诉您正在使用 getLambda()
。
如果您使用 C++20,解决方案很简单。您可以将 lambda 的定义移至
decltype
,假设它没有捕获:
struct LambdaWrapper {
using LambdaType = decltype( []() {
std::cout << "Lambda is called" << std::endl;
});
LambdaType getLambda() {
return {};
}
};
请参阅编译器资源管理器中的实时示例。
适用于旧标准的更通用解决方案是将 lambda 表达式移至单独的作用域,例如基类:
// note: You can also put getLambda() into a namespace, not into a class.
// I suspect your example is overly minimal and you can't actually do that.
struct LambdaProvider {
auto getLambda() {
return []() {
std::cout << "Lambda is called" << std::endl;
};
}
};
struct LambdaWrapper : LambdaProvider {
using LambdaType = decltype(std::declval<LambdaProvider>().getLambda());
LambdaType getLambda() {
return {};
}
};
请参阅编译器资源管理器中的实时示例。
您甚至可以将
LambdaProvider
转换为 CRTP(奇怪的重复模板模式),以便您可以访问其中的 LambdaWrapper
的成员函数。