在c++中使用范围是否可取?

agyaoht7  于 2022-12-05  发布在  其他
关注(0)|答案(4)|浏览(152)

我发现大多数C++ STL算法的传统语法令人讨厌;使用它们的过程很长,这只是一个小问题,但它们总是需要对现有对象进行操作,这极大地限制了它们的可组合性。
我很高兴看到stl中范围的出现;然而,从C20开始,它存在严重的缺点:标准库的不同实现对此的支持各不相同,并且range-v3中存在的许多内容没有被C20使用,例如(令我非常惊讶的是)将视图转换为向量(对我来说,如果我不能将计算结果存储在向量中,这将使所有这些内容变得有点无用)。
另一方面,使用range-v3对我来说也不太理想:它的文档记录很差(我不同意所有的东西都是不言自明的),更严重的是,C++20-range的概念与range-v3的不同,所以我不能说,好吧,让我们坚持使用range-v3;这在某个时候会成为标准。
那么,我是否应该使用这两种方法中的任何一种呢?或者这一切都不值得,因为依赖于std range或range-v3,使我的代码难以维护和移植?

tjrkku2a

tjrkku2a1#

在c中使用范围是否可取?
是的,我知道
而且range-v3中的很多东西都没有进入C
20,比如(令我非常惊讶的是),将视图转换为向量
是的。但是std::ranges::to已经被C23采用了,它的功能更强大,并且可以很好地与C23的stl容器的范围版本构造器一起工作。
那么,我应该使用这两个中的任何一个吗?
您应该使用标准库<ranges>
此外,C++23不仅带来了更多的适配器,如join_with_viewzip_view等,而且还带来了更强大的特性,如管道支持用户自定义范围适配器(P2387),以及格式化范围(P2286),你唯一需要做的就是等待编译器实现它。你可以参考cppreference来获得最新的编译器支持。

cbjzeqam

cbjzeqam2#

我建议使用range-v3而不是std::ranges。缺少了太多的东西(至少在实现c++23之前),所以根本不值得使用std::ranges。

另一方面,使用range-v3对我来说也不太理想:它的文档记录很差(我不同意其中的所有内容都是不言自明的),
从这些补充材料中学习range-v3是很容易的,如果你想要更多的话,你可以随时买这本书。
此外,range-v3是开源的,所以你可以让源代码成为你的文档。
更严重的是,C++20-range的概念和range-v3的不同,所以我不能说,好吧,我们还是用range-v3这在某个时候会成为标准。
我怀疑这些改变会有什么影响,主要的问题是range-v3和std::ranges不能合并,但是改变名称空间应该是将range-v3移植到std::ranges 23的大部分工作。
使我的代码难以维护
没有range的代码太难了。使用range-v3保存了大量的时间,特别是在新编写的代码中消除bug所花费的时间,以及理解过去编写的代码并修改它所花费的时间。我认为不使用range-v3的唯一原因是维护现有代码库的约定。

egmofgnx

egmofgnx3#

简单示例:一亿个随机整数值的排序向量

#include <iostream>
#include <chrono>
#include <ranges>
#include <random>
#include <vector>
#include <algorithm>

int main(int argc, char **argv) {

    const int START = 1, END = 50, QUANTITY = 100000000;

    std::random_device dev;
    std::mt19937 rng(dev());
    std::uniform_int_distribution<std::mt19937::result_type> dist6(START, END);

    std::vector<int> vec;
    vec.reserve(QUANTITY);

    for (int i = 0; i < QUANTITY; i++) {
        vec.push_back(dist6(rng));
    }

    std::vector<int> original_copy = vec;

    auto start_test1 = std::chrono::high_resolution_clock::now();
    std::ranges::sort(vec);
    auto end_test1 = std::chrono::high_resolution_clock::now();
    auto duration_test1 = std::chrono::duration_cast<std::chrono::milliseconds>(end_test1 - start_test1).count();

    auto start_test2 = std::chrono::high_resolution_clock::now();
    std::sort(original_copy.begin(), original_copy.end());
    auto end_test2 = std::chrono::high_resolution_clock::now();
    auto duration_test2 = std::chrono::duration_cast<std::chrono::milliseconds>(end_test2 - start_test2).count();

    std::cout << "test std::ranges::sort, vector was sorted in  " << duration_test1 << " milliseconds." << std::endl;
    std::cout << "test std::sort, vector was sorted in  " << duration_test2 << " milliseconds." << std::endl;

    if (duration_test1 > duration_test2) {
        std::cout << "std::sort is " << duration_test1 - duration_test2 << " milliseconds faster" << std::endl;
    } else {
        std::cout << "std::ranges::sort is " << duration_test2 - duration_test1 << " milliseconds faster" << std::endl;
    }

    return 0;
}

输出:

test std::ranges::sort, vector was sorted in  175319 milliseconds.
test std::sort, vector was sorted in  45368 milliseconds.
std::sort is 129951 milliseconds faster

在我看来,std::ranges有些奇怪,也许它比标准算法更容易使用,但性能可能会更好

koaltpgm

koaltpgm4#

作为一个范围成瘾者,我这次要再次回答否定的。
你花在开发上的大部分时间都花在了增量编译一个编译单元上。使用范围会大大增加这些编译时间。msvc的编译速度明显更快,当我切换gcc或clang时,这是无法忍受的。
你不能通过设置编译墙来解决这个问题,因为你几乎总是要推导出你的范围的类型。所以即使你不修改范围代码,你也会被缓慢的编译时间所困扰。
让模板编译也是浪费时间。在使用Python的迭代之后,你真的开始注意到静态类型系统的任意限制。有很多怪癖你必须通过艰苦的方式来学习。
C++的范围相当复杂。我试着不那么书呆子气,如果你也是,建议远离。
声明式代码比命令式代码更容易阅读和维护。函数式编程将所有容易出错的面向细节的代码从代码中推到库中。但代价是什么呢?mapreducefilter都很容易命令式实现,但我需要我的group_bysplit

相关问题