Search code examples
c++stringboostrange

Boost::adaptors::transformed fails to return strings to boost::any_range


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.


Solution

  • 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
    >;