要检查向量v
是否为空,我可以使用std::empty(v)
或v.empty()
。我看了cppreference上的签名,但我缺乏理解它们的知识。它们是如何相互联系的?一个实现调用另一个实现吗?
我知道一个来自容器库,另一个来自迭代器库,但仅此而已。
std::vector::empty与std::empty的区别
Container::empty
成员函数与std::empty
自由函数(模板)的差异与Container::size
、std::size
、Container::data
、std::data
、Container::begin
、std::begin
与Container::end
、std::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)
这个重载有如下效果:
- 返回
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容器类的任何允许的专门化,或者对于自定义容器类,这种关系必须保持,这样就限制了标准库的编写者被允许做的事情。