c++ 无法通过管道将字符串上的split_view传输到transform(to< string>)

dgenwo3n  于 2023-02-14  发布在  其他
关注(0)|答案(1)|浏览(114)

(包括c++17c++20,以防解决方案/变通方法不同。)
下面的代码可以工作,

#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"}));
}

但是在X1 M2 N1 X分支中将X1 M0 N1 X切换到X1 M1 N1 X使其失败。
lambda的作用与to<std::string>对象本身有什么不同?

k3bvogb1

k3bvogb11#

lambda的作用与to<std::string>对象本身有什么不同?
to<std::string> * 不是 * 对象,它实际上是一个示例化的 * 函数指针 *,它接受一个可默认构造的标签,并返回一个记录指定容器类型的闭包对象(例如,示例中的std::string)。
所以它的类型可以大致拼写为

/* some range adaptor closure type */ (*)(tag_t)

为了使r | to<std::string>工作,range-v3在tag_t中额外定义了一个管道操作符,它接受这种函数指针类型,大致如下:

struct tag_t
{
  friend Container
  operator|(R&& r, /* some range adaptor closure type */ (*)(tag_t)) {
    return /* Immediately default-constructs and invokes a callable object */
  }
};

在您的示例中,当启用#if 0分支时,to_string是接收tag_t的函数指针,这就是为什么在调用to_string(*strs.begin())时会出现错误,因为*strs.begin()返回一个范围,该范围无法转换为tag_t
要实现上述功能,可以使用to<std::string>()(注意这里的括号)直接获取范围适配器闭包对象。
值得注意的是,C++23 std::ranges::to目前 * 不 * 支持省略括号的语法,标准委员会曾讨论过是否支持这一特性(参见issues/527),但遗憾的是,最近被否决了。

相关问题