包装 STL 习惯用法以提高可读性是一个好主意吗?

发布于 2024-09-12 00:45:16 字数 1052 浏览 11 评论 0原文

我目前正在开发一个 C++ 项目,该项目需要尽可能少的外部依赖项,因此我几乎坚持使用 STL 和 Boost。到目前为止,当谈到 C++ 时,我几乎完全生活在 Qt 领域。一般来说,如果可以的话,我倾向于使用 C# 和 Python。

今天我想检查 std::vector 是否包含某个项目。对于 Qt,我会这样做:

QList< int > list;
list.append( 1 );
list.append( 2 );
list.append( 3 );

if ( list.contains( 2 ) )
{
    // do something
}

漂亮且可读。但 std::vector 没有 contains 方法,这令人惊讶。好吧...类似这样的东西的 STL 习惯用法是什么?环顾四周,似乎是这样的:(

std::vector< int > list;
list.push_back( 1 );
list.push_back( 2 );
list.push_back( 3 );

std::vector< int >::const_iterator result =
    std::find( list.begin(), list.end(), 2 );

if ( result != list.end() )
{
    // do something
}

对我来说)这很难读,而且太冗长了。因此,我发现自己编写了一个实用函数,它接受一个向量和一个值,并根据是否找到该值返回 bool 。基本上,是一个模板化的 contains() 方法;上述 std::find 调用的包装器。然后我可以以类似于 Qt 示例的方式使用它。

我想到了几个类似的实用函数,它们会包装其他 STL 习惯用法,没有其他原因,只是(感知到的)可读性的增加。我想知道的是...这是一个坏主意吗?其他人也这样做吗?我是否遗漏了一些重要的东西?代码在某一时刻将是 OSS,我宁愿不做一些其他 C++ 开发人员会觉得奇怪的事情。

I'm currently working on a C++ project that needs to have as few external dependencies as possible, and thus I'm pretty much sticking to STL and Boost. Until now, I've been almost exclusively living in Qt-land when it comes to C++. In general I tend to use C# and Python when I can.

Today I wanted to check whether a std::vector contained a certain item. With Qt, I'd do this like so:

QList< int > list;
list.append( 1 );
list.append( 2 );
list.append( 3 );

if ( list.contains( 2 ) )
{
    // do something
}

Nice and readable. But std::vector has no contains method, which was a surprise. Ok... what would the STL idiom for something like that be? Searching around, it seems to be this:

std::vector< int > list;
list.push_back( 1 );
list.push_back( 2 );
list.push_back( 3 );

std::vector< int >::const_iterator result =
    std::find( list.begin(), list.end(), 2 );

if ( result != list.end() )
{
    // do something
}

That (to me) is hardly readable and much too verbose. So I found myself writing a utility function that takes a vector and a value and returns bool depending on whether the value was found or not. Basically, a templated contains() method; a wrapper for the above std::find call. I can then use that in a way that is similar to the Qt example.

I have several similar utility functions in mind that would wrap other STL idioms for no other reason but a (perceived) increase in readability. What I want to know is... is this a bad idea? Do other people do the same? Am I missing something crucial? The code will be OSS at one point, and I'd rather not do something idiosyncratic that other C++ devs would find strange.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

你对谁都笑 2024-09-19 00:45:16

boost 让它变得更加整洁。我从来不用STL
不再是基于迭代器的算法了。范围
基于算法是一个更简洁的抽象
并产生更清晰的代码。

#include <boost/range/algorithm/find.hpp>

void foo(){
    std::vector<int> list;
    ...
    ...
    boost::find(list, 2) != list.end()
}

boost makes it much neater. I never use the STL
iterator based algorithms anymore. The range
based algorithms are a much neater abstraction
and result in much cleaner code.

#include <boost/range/algorithm/find.hpp>

void foo(){
    std::vector<int> list;
    ...
    ...
    boost::find(list, 2) != list.end()
}
夏夜暖风 2024-09-19 00:45:16

编写实用函数并没有什么错,它可以帮助您并使您的代码更加清晰。其他人也这样做。 Boost 库 是此类实用函数和类的最大集合。

更值得一提的是,C++ 标准明确提议扩展标准库(17.3.1.2/1):

该库可以通过 C++ 程序进行扩展。每个条款(如适用)描述了此类扩展必须满足的要求。此类扩展通常是以下之一:

  • 模板参数
  • 派生类
  • 满足接口约定的容器、迭代器和/或算法

There is nothing wrong in writing the utility functions that will help you and will make your code cleaner. Other people do the same. Boost library is the biggest set of such utility functions and classes.

More to say C++ Standard explicitly proposes to extend the Standard Library (17.3.1.2/1):

The library can be extended by a C++ program. Each clause, as applicable, describes the requirements that such extensions must meet. Such extensions are generally one of the following:

  • Template arguments
  • Derived classes
  • Containers, iterators, and/or algorithms that meet an interface convention
眼藏柔 2024-09-19 00:45:16

我想说这绝对是个好主意。 C++ STL 缺少许多 Python/C# 程序员对标准库的期望。如果您可以通过采用 2-3 行 STL 方法并将其设为单个函数来使代码更具可读性,那就继续吧!

这是非常相似问题的另一个示例:我经常想将 int 转换为 std::string。令我惊讶的是,没有使用 STL 执行此操作的简洁方法。因此,我编写了一个 toStr 函数,该函数运行将 int 放入 stringstream 并返回结果 所需的 2-3 行字符串

编辑:为了澄清,我建议在创建自己的解决方案之前寻找 boost 解决方案。我的示例旨在演示 STL 的局限性,但有另一种解释:“无论 STL 缺少什么,boost 都有。”

I'd say it's definitely a good idea. The C++ STL is missing a lot of what Python/C# programmers have come to expect from a standard library. If you can make your code more readable by taking that 2-3 line STL approach and making it a single function, go ahead!

Here's another example of a very similar issue: I often want to convert an int to a std::string. To my surprise, there's no concise way of doing this using the STL. So, I wrote a toStr function that runs the 2-3 lines required to put an int into a stringstream and return the resulting string.

Edit: To clarify, I recommend looking for boost solutions before creating your own. My example was intended to demonstrate the limitations of the STL, but has the alternative interpretation of, "whatever the STL is missing, boost has."

笑,眼淚并存 2024-09-19 00:45:16

类似地,在我当前的项目中,我们有一个名为:stlutils.h 的文件,其中包含一些方法,例如 contains()。实现为:

template<class Container, class T>
bool contains(const Container& c, const T& value) {
   return std::find(c.begin(), c.end(), value) != c.end();
}

还有更多功能,但我想你明白了

Similar enough, in my current project, we have a file called: stlutils.h, which contains some methods, such as contains(). Implemented as:

template<class Container, class T>
bool contains(const Container& c, const T& value) {
   return std::find(c.begin(), c.end(), value) != c.end();
}

There are more functions, but I think you get the point

白鸥掠海 2024-09-19 00:45:16

其他答案指出,您可以编写实用函数来为您执行此操作,这是您需要它的好主意。但我想我应该指出一个重要的观点:STL 是围绕算法效率而设计的。几乎所有 STL 操作都有标准规定的大 O 效率要求。

如果vector有一个contains()成员,那么调用它肯定会是O(n),因为vector是一个简单的连续列表。由于它也很方便,因此可能会鼓励程序员定期使用它,即使在大型数据集上也是如此,从而鼓励设计算法性能较差的应用程序。在 contains() 的情况下,如果查找容器是否包含某个元素很重要,并保证所有元素都是唯一的,则 std::set 几乎肯定是更好的选择,查找效率为 O(log n),对于 std::unordered_set 甚至为 O(1)。

所以我个人的观点是:学习 STL 提供的所有容器和功能,您会发现虽然它很简洁,但它鼓励更高效的编程风格。你在问题中问你是否遗漏了一些东西,我会说是的 - 你想更仔细地考虑你使用的容器。这些天我经常使用 set 而不是 vector

The other answers have made the point that you can write utility functions to do this for you, and that's a good idea where you need it. But I thought I'd point out an important point: the STL is designed around algorithmic efficiency. Nearly all operations with the STL have a standard-mandated big-O efficiency requirement.

If vector had a contains() member, it would certainly be O(n) to call, since vector is a simple contiguous list. Since it is also convenient, it might encourage programmers to use it regularly, even on large datasets, encouraging the design of applications with poor algorithmic performance. In the case of contains(), if it's important to look up if a container holds a certain element, with the added guarantee that all the elements are unique, std::set is almost certainly a better choice, with O(log n) efficiency lookups, or even O(1) for std::unordered_set.

So my personal view: learn all the containers and features the STL offers, and you'll find while it is terse, it encourages a more efficient programming style. You ask in the question if you're missing something, and I would say yes - you want to think more carefully about the container you use. I use set instead of a vector regularly these days.

稚然 2024-09-19 00:45:16

我不太喜欢包装纸,但如果它们对你有帮助,那就去做吧。我想随着时间的推移,您会发​​现除了 std::vector 之外,您还希望将实用程序函数与其他容器一起使用。最终你的实用函数变得如此通用,以至于你还不如直接使用 std::find 。

但您确定您使用的是正确的容器吗? std::set 有一个方法 count(),本质上等价于 contains()。它是 O(log(n)),而不是 O(n)。

I'm not a big fan of wrappers, but if they help you out, go for it. I think you'll find over time that you'll want to use your utility function with other containers besides std::vector. Eventually your utility function becomes so generic that you might as well use std::find directly.

But are you sure you're using the right container? std::set has a method count(), which is essentially equivalent to contains(). And it is O(log(n)), rather than O(n).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文