(Including both c++17 and c++20 just in case the solution/workaround is different.)
The code below works,
#include <cassert>
#include <range/v3/algorithm/equal.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/split.hpp>
#include <range/v3/view/transform.hpp>
#include <string>
#include <vector>
using namespace ranges;
using namespace ranges::views;
int main() {
auto to_string =
#if 0
to<std::string>
#else
[](auto x){ return to<std::string>(x); }
#endif
;
std::string str{"hello world"};
auto strs = str | split(' ');
assert(to_string(*strs.begin()) == "hello");
assert(equal(str | split(' ') | transform(to_string),
std::vector{"hello", "world"}));
}
but switching the 0
to 1
in the #if
branch makes it fail.
What is the lambda doing differently than the to<std::string>
object itself?
What is the lambda doing differently than the
to<std::string>
object itself?
to<std::string>
is not an object, it is actually an instantiated function pointer, which takes a default-constructible tag and returns a closure object that records the specified container type (i.e. std::string
in your example).
So its type can be roughly spelled as
/* some range adaptor closure type */ (*)(tag_t)
To make r | to<std::string>
work, range-v3 additionally defines a pipe operator inside the tag_t
that accepts this function pointer type, roughly as follows:
struct tag_t
{
friend Container
operator|(R&& r, /* some range adaptor closure type */ (*)(tag_t)) {
return /* Immediately default-constructs and invokes a callable object */
}
};
In your example, when the #if 0
branch is enabled, to_string
is a function pointer that receives tag_t
. This is why you get an error when invoking to_string(*strs.begin())
, because *strs.begin()
returns a range, which cannot be converted to tag_t
.
To make the above work, you can use to<std::string>()
(note the parentheses here)to get a range adaptor closure object directly.
It is worth noting that C++23 std::ranges::to
does not currently support the syntax for omitting parentheses. The standards committee has discussed whether to support this feature (see issues/527), but unfortunately, it was rejected recently.