std::vector::empty与std::empty的区别

  • 本文关键字:std empty 区别 vector c++ std
  • 更新时间 :
  • 英文 :


要检查向量v是否为空,我可以使用std::empty(v)v.empty()。我看了cppreference上的签名,但我缺乏理解它们的知识。它们是如何相互联系的?一个实现调用另一个实现吗?

我知道一个来自容器库,另一个来自迭代器库,但仅此而已。

std::vector::empty与std::empty的区别

Container::empty成员函数与std::empty自由函数(模板)的差异与Container::sizestd::sizeContainer::datastd::dataContainer::beginstd::beginContainer::endstd::end的差异相同。

在所有这些情况下,对于任何标准容器,自由函数(如std::empty)只是调用相应的成员函数。存在free函数的目的是在容器(也包括std::initializer_list)和数组之间提供统一的接口。数组不能像类模板那样拥有成员函数,因此它们为这些自由函数提供了专门的重载。

如果你用模板化的容器类型编写代码,那么你应该使用free函数,以便能够支持数组作为模板化类型。如果类型没有被模板化,那么选择使用成员函数还是自由函数,除了可能重构为模板(或只是普通数组)的便利性之外,没有什么区别。

std::empty有三个重载,但std::empty(v)对矢量v使用的是第一个:

template <class C>
constexpr auto empty(const C& c) -> decltype(c.empty()); // (since c++17, until c++20)
template <class C>
[[nodiscard]] constexpr auto empty(const C& c) -> decltype(c.empty());
(since C++20) // (since c++20)

这个重载有如下效果:

  1. 返回c.empty()

在这个例子中,std::empty(v)v.empty()的效果是一样的。

std::empty返回调用std::vector::empty的结果。

std::empty对于容器可能提供成员函数empty()(对于提供成员函数empty的类型,std::empty提供默认实现)的场景是有用的,但是对于不提供该函数的自定义类型,您可以在命名空间范围内提供empty函数以供模板使用;由于参数依赖查找,与形参在同一名称空间中的函数将用作回退:

namespace Custom
{
struct Container
{
bool m_empty;
};
constexpr bool empty(Container const& c) // custom implementation for our own type
{
return c.m_empty;
}
}
template<class T>
void PrintEmpty(char const* containerName, T&& container)
{
using namespace std;
std::cout << containerName << " is " << (empty(container) ? "empty" : "not empty") << 'n';
}
int main()
{
PrintEmpty("std::vector<int>()", std::vector<int>());
PrintEmpty("Container{}", Custom::Container{});
PrintEmpty("Container{ true }", Custom::Container{ true });
}

从语言角度来说,c++ 20标准规定容器a有其a.empty()成员函数返回true当且仅当a.begin() == a.end()([container.requirements.general])。

std::empty()非成员函数在[iterator.range]中指定。重载constexpr auto empty(const C& c)"返回:c.empty(). "

因此,在标准中,非成员函数是根据成员函数指定的,而不是相反。一般来说,这并不意味着实现需要让非成员函数实际调用成员函数,只要它"表现得像"即可。在这种情况下,对于STL容器类的任何允许的专门化,或者对于自定义容器类,这种关系必须保持,这样就限制了标准库的编写者被允许做的事情。

最新更新