Consider the code below:
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;
}
I'm using auto for both LambdaWrapper::getLambda() return type and for the argument of the useLambda() function. But actually in this code the only type is used, and that is what LambdaWrapper::getLambda() returns, so I can define an alias for the type:
struct LambdaWrapper {
auto getLambda() { ... }
static LambdaWrapper* get();
};
using LambdaType = decltype(LambdaWrapper::get()->getLambda());
void useLambda(const LambdaType &lambda);
Now I wish to make this alias to be a part of the LambdaWrapper class:
struct LambdaWrapper {
auto getLambda() { ... }
static LambdaWrapper* get();
using LambdaType = decltype(LambdaWrapper::get()->getLambda());
};
void useLambda(const LambdaWrapper::LambdaType &lambda);
But now I'm getting
error: use of ‘auto LambdaWrapper::getLambda()’ before deduction of ‘auto’
How could I define this alias inside the class?
Update: I still believe that my question does not need any additional details or clarity, but some responders disagree with that. So let me add more details.
My problem starts with the question here: How to define a type-erased ranges::view?, where I'm asking how to type-erase a complex composition of range-views that use lambdas (possibly capturing), and where the type of this composition may change over time if more views would be added or changed. I see one of the solutions of that problem in the following strategy:
- Define an inline method (in the body of the class) that returns the actual complex composition of views with no type erasure.
- Let the function deduct the actual type.
- Define an alias for the return type of that method using
decltype. - Use that alias in any function that consumes that complex composition of views; the alias would hide that complexity, and even if the views would change, the consumer's code wouldn't.
I could do that by defining this alias as a type outside of the scope of the class. I could do that creating one more level of indirection (employing either inheritance or a nested class). But it sounds illogical that my goal cannot be achieved without hacks like inheriting from an artificial class. So the purpose of asking this question is to find the most elegant solution to implement the strategy described above.
The issue is that classes are parsed in two passes. One the first pass, the compiler sees the declaration
auto getLambda()(not a definition), andusing LambdaType = decltype(LambdaWrapper::get()->getLambda());, however, since no definition ofgetLambais available yet, parsing fails. This is why the compiler tells you that you are usinggetLambda()before the return type could be deduced.If you are using C++20, the solution is trivial. You can just move the definition of your lambda into
decltype, assuming that it has no captures:See live example at Compiler Explorer.
A more general solution which works with older standards is to move the lambda expression into a separate scope, such as a base class:
See live example at Compiler Explorer.
You can even turn
LambdaProviderinto a CRTP (curiously recurring template pattern) so that you can access the member functions ofLambdaWrapperinside of it.