I cannot seem to pass std::optional::value to std::views::transform.
However, I can pass std::optional::has_value without any issues:
#include <optional>
#include <ranges>
#include <vector>
int main () {
std::vector<std::optional<int>> myVec{{1,2,3}};
const auto result = myVec
| std::views::filter(&std::optional<int>::has_value)
| std::views::transform(&std::optional<int>::value);
return 0;
}
As an example, here is the error I get with x86-64 clang 16.0.0 and passing the -std=c++20 flag:
<source>:15:11: error: no matching function for call to object of type 'const _Transform'
| std::views::transform(&std::optional<int>::value);
^~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/ranges:891:2: note: candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter '_Args'
operator()(_Args&&... __args) const
^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/ranges:2057:2: note: candidate function template not viable: requires 2 arguments, but 1 was provided
operator() [[nodiscard]] (_Range&& __r, _Fp&& __f) const
^
1 error generated.
Compiler returned: 1
Do you know what is going on?
Natually, as a workaround, I can use a lambda, though that doesn't feel nearly as satisfactory:
const auto thisWorks = myVec
| std::views::filter(&std::optional<int>::has_value)
| std::views::transform([] (const auto& opt) {return opt.value();});
The problem becomes very clear when compiling with GCC, which yields the error:
Pay special attention to
<unresolved overloaded function type>.&std::optional<int>::valuetakes the address of an unresolved overloaded function type because this member function has overloads forconst, non-const, lvalue references, and rvalue references. In total,std::optional::valuehas four overloads, and the compiler doesn't know which one to choose when you take its address.You can suppress the error as follows:
See live example at Compiler Explorer.
However, while this technically compiles, it's not pretty, and
valueis not an addressable function. This means that taking its address has unspecified effect, and the program might even be ill-formed. See also: Can I take the address of a function defined in standard library?You should use your workaround with lambdas for both
filterandtransform. It is the idiomatic and correct solution, even if it isn't as concise.