std::vector::empty 和 std::empty 之间的区别

Difference between std::vector::empty and std::empty

要检查向量 v 是否为空,我可以使用 std::empty(v) or v.empty()。我查看了 cppreference 上的签名,但缺乏理解它们的知识。它们之间有什么关系?一种实现调用另一种实现吗?

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

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. returns c.empty()

因此,std::empty(v)v.empty()在这种情况下具有相同的效果。

Difference between std::vector::empty and std::empty

Container::empty成员函数和std::empty自由函数(模板)的区别与Container::sizestd::sizeContainer::data的区别相同, std::dataContainer::beginstd::beginContainer::endstd::end.

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

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

std::empty returns 调用结果 std::vector::empty.

std::empty 适用于容器可能会或可能不会提供成员函数的场景 empty() 对于提供成员函数的类型 emptystd::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 });
}

到language-lawyer一点,C++20标准说容器a有它的a.empty()成员函数return true如果和仅当 a.begin() == a.end() ([container.requirements.general]).

std::empty() non-member 函数在 [iterator.range] 中指定。重载 constexpr auto empty(const C& c)Returns: c.empty().”

因此,在标准中,non-member 函数是根据成员函数指定的,反之亦然。一般来说,这并不意味着实现需要 non-member 函数实际调用成员函数,只要它“表现得好像”。在这种情况下,关系必须适用于任何允许的 STL 容器特化 类,或自定义容器 类,从而限制库的编写者被允许做的事情。