I would like to store a range as a field in a class, so that I could reuse it several times later on. However, unlike local variables, I cannot simply specify it type as auto
. On the other hand, the types of ranges that the library creates are very complex. It would take me disproportionately long time to figure out the correct type by hand + it would be unmaintainable in the future if I would choose to change how the range is obtained.
So, I thought, maybe I could use decltype
to help myself:
class MyClass {
public:
using MyRange = decltype(std::declval<std::vector<int*>>() | ranges::v3::view::filter([=](int* elem) { return true; }));
MyRange range;
}
(note: my actual std::declval
is actually more complex, but I wanted to make the example brief.)
But I get an error:
a lambda cannot appear in an unevaluated context
So, my question is:
decltype
working?The language is being helpful here: if the lambda were allowed in decltype
, it wouldn't help you, because there would be no way for you to produce a value of type MyRange
other than via default-initialization. Since very occurrence of a lambda expression has a unique type, you couldn't produce a function object of the correct type to pass to view::filter
to get it to return something you could store in a MyRange
.
The workaround is to "don't do that"; e.g., store your function object somewhere and refer to it in the decltype
. In C++17, for example:
struct MyClass {
static constexpr auto pred = [](int* elem) { return true; };
using MyRange = decltype(std::declval<std::vector<int*>&>() | ranges::v3::view::filter(pred));
MyRange range;
};
Note the use of std::vector&
. This is required as explained in Explicit range-v3 decltype evaluates to void?