I've come across a problem with boost::any_range
losing strings when assigned a return value from boost::adaptors::transformed
. Here is a sample code:
#include <iostream>
#include <string>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
int main() {
using my_range = boost::any_range <
const std::string,
boost::forward_traversal_tag
>;
std::vector<std::string> V = {"foo", "bar"};
my_range range = V | boost::adaptors::transformed([](auto) { return "Hello World!\n"; });
for (const auto& v : range) std::cout << v;
}
The output is empty for some reason. When I replace strings with some other type like int
or double
, everything works as expected. Also, the string "Hello World"
does get printed out if I do not convert the range returned from the operator|
(by replacing my_range range
with auto range
. What is the reason for such behavior? Is it a bug?
The code was compiled with MSVC using Visual Studio 22. The version of Boost is 1.80.
any_range
is deducing the reference type of your type-erased range as const std::string&
, but your lambda returns by value, so you end up getting a dangling reference. You can fix this by making the reference type of the range a value.
Additionally, if the documentation is correct then boost::adaptors::transform
is a single pass range, so your tag type is incorrect.
The definition of my_range
should be:
using my_range = boost::any_range <
const std::string,
boost::single_pass_traversal_tag,
const std::string
>;