【问题标题】:C++ range-v3: trying to chain together transformsC ++ range-v3:尝试将转换链接在一起
【发布时间】:2019-05-24 03:49:02
【问题描述】:

我对范围库完全陌生,所以我不应该对这段代码没有编译并且我不知道为什么感到惊讶:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>

#include <range/v3/all.hpp>
#include <range/v3/view/all.hpp>
using namespace ranges::v3;


std::ifstream open_file(const std::string &filename) {
    return std::ifstream{filename};
}

int count_lines(std::ifstream &in) {
    return std::count(std::istreambuf_iterator<char>{in},
                      std::istreambuf_iterator<char>{}, '\n');
}

std::vector<int>
count_lines_in_files(const std::vector<std::string> &filenames) {
    auto a1 = filenames | view::transform(open_file) | view::transform(count_lines);
    return a1;
}

int main() {
    const std::vector<std::string> files{"listing1_1.cpp",
                                         "listing1_2.cpp",
                                         "listing1_4.cpp",
                                         "listing1_5.cpp"};
    const auto result = count_lines_in_files(files);
    std::cout << ranges::view::all(result) << '\n';
}

看来投诉是关于a1,编译器告诉我“错误:变量的类型不完整'void'。”

谁能看到我做错了什么,或者告诉我如果可能的话如何正确地将它们链接在一起?

提前致谢!

【问题讨论】:

  • 当我尝试编译它时,之后会出现更多错误消息,包括试图准确解释问题所在的 static_assert。这不会编译,因为count_lines(open_file(*begin(files))) 不会编译。

标签: c++ c++17 range-v3


【解决方案1】:

正如Porsche9II 所述,“std::ifstream 没有复制构造函数”。您可以在此处找到有关此主题的更多信息:

Why are iostreams not copyable?

C++11 为std::basic_ifstream 引入了一个移动构造函数(6),所以你可以写

auto open_file(const std::string &filename) {
    return std::ifstream{filename};
}

auto count_lines(std::ifstream &&in) {
    return std::count(std::istreambuf_iterator<char>{in},
                      std::istreambuf_iterator<char>{}, '\n');
}

可测试HERE

【讨论】:

  • 不错的一个 - 比我的解决方案更好:-) 并且警告消失了 gcc 9.1.0 ...
  • @Porsche9II 谢谢,同时删除了有问题的 ::v3 作品,使用 Clang。
  • 优秀。非常感谢。这来自 Manning 的《C++ 函数式编程》一书(他出版了著名的 Scala 函数式编程一书)。作者建议将代码从打开文件和读取行的一个函数拆分为我尝试的两个函数方法。不过,@Porsche9II 让我想知道:传递文件流是个好主意吗?这样做而不是将它们包含在一个功能中是否存在任何固有风险? (这本书的作者还说他所有的代码都在 gitlab 中,但严重缺乏。到目前为止没有留下深刻印象。)
  • @Sebastian 在我链接的问答中,您可以找到comment,其中引用了 Scott Meyers 关于未实现复制构造函数的原因。移动语义应该可以解决这些问题,但恐怕我仍然不太熟悉范围库来提供有价值的提示。
【解决方案2】:

std::ifstream 没有复制构造函数 - 通过函数返回 std::ifstream 不是一个好主意。一种可能的解决方案:打开和计数应该在一个函数中进行。

【讨论】:

  • 这实际上是在 Manning 的 C++ 中的函数式编程一书中,因为他们按照您的建议专门在一个函数中完成了它,但随后建议根据我的问题将其拆分为两个函数。现在我想起来了,你说得对:从函数返回 ifstream 似乎是个坏主意。
猜你喜欢
  • 2021-09-11
  • 1970-01-01
  • 2019-12-16
  • 1970-01-01
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
相关资源
最近更新 更多