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)
此重载具有以下效果:
- returns
c.empty()
因此,std::empty(v)
和v.empty()
在这种情况下具有相同的效果。
Difference between std::vector::empty and 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
)和数组之间提供统一的接口。数组不能像 class 模板那样具有成员函数,因此它们具有针对这些自由函数的专门重载。
如果您正在使用模板化容器类型编写代码,那么您应该使用 free 函数以便能够支持数组作为模板化类型。如果类型不是模板化的,那么除了可能重构为模板(或只是普通数组)的便利性之外,使用成员函数或自由函数的选择没有区别。
std::empty
returns 调用结果 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 });
}
到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 容器特化 类,或自定义容器 类,从而限制库的编写者被允许做的事情。
要检查向量 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)
此重载具有以下效果:
- returns
c.empty()
因此,std::empty(v)
和v.empty()
在这种情况下具有相同的效果。
Difference between std::vector::empty and 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
)和数组之间提供统一的接口。数组不能像 class 模板那样具有成员函数,因此它们具有针对这些自由函数的专门重载。
如果您正在使用模板化容器类型编写代码,那么您应该使用 free 函数以便能够支持数组作为模板化类型。如果类型不是模板化的,那么除了可能重构为模板(或只是普通数组)的便利性之外,使用成员函数或自由函数的选择没有区别。
std::empty
returns 调用结果 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 });
}
到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 容器特化 类,或自定义容器 类,从而限制库的编写者被允许做的事情。