重载 STL 函数
Overloading STL function
我有这样的代码:
set<array<int, 3>> s;
int ar[3] = {1,2,3};
s.insert(ar);
auto it = s.find(ar);
以及 IDE 的消息 no instance of overloaded function insert/find
。如果我使用 std::array
没问题,::insert
和 ::find
的工作方式相同。
但是,如果我想使用这些 C 数组 T[N]
或在 set should return 迭代器中查找带有 std::array
的函数,如果三个元素中的两个相等。或者 set::insert
不会插入新数组,如果它是存在的排列,我的意思是 s.insert({1,2,3})
- 已经添加,s.insert({3,2,1})
- return {1,2,3}
上的迭代器。
问题是如何重载STD函数?不是在这段代码中,而是在一般情况下?欢迎任何 link 或真实代码示例。对于有经验的程序员来说,这可能是一个非常简单的问题)但是有很多运算符重载的例子,但对于 STL 却没有。谢谢。
我不认为 C++ 赋予您这样做的权利。有关更多信息,您可能会得到这个 answer 对您的情况有用。
希望对您的问题有所帮助。
您不能在 class 定义之外为 class 的成员函数声明额外的重载。该语言不为其提供语法。由于您无法修改标准库 headers 中的 class 定义,因此您也无法为其添加额外的重载。
std
命名空间中的自由函数不能被重载。它有语法(与任何自由函数重载的工作方式相同),但这样做会导致未定义的行为,因为它在标准中被明确禁止,请参见 [namespace.std]/1.
通常(有例外)允许的是为 std
命名空间中的实体定义 模板特化 ,但前提是该特化依赖于 user-defined 类型,不适用于成员函数、成员函数模板或成员 class 模板。请参阅上面链接的引用和后续段落的其余部分。
使用 std
命名空间内部特化的常见示例是 std::hash
用作无序关联容器中的哈希函数:
struct my_type {
//...
};
namespace std {
template<>
struct hash<my_type> {
auto operator()(my_type const& x) const noexcept {
//...
}
};
}
但是,如果 my_type
被 int*
、int[3]
或 std::array<int, 3>
或类似的任何东西替换,即使是这样的东西也是不允许的,因为不依赖于user-declared类型。
如果您想从 built-in 数组创建 std::array
,您将能够在 C++20 中使用 std::to_array
:
set<array<int, 3>> s;
int ar[3] = {1,2,3};
s.insert(std::to_array(ar));
auto it = s.find(std::to_array(ar));
在 C++20 之前,您可以在 #include<experimental/array>
中将函数作为 std::experimental::to_array
提供,或者您可以自己定义它(来自 cppreference.com;需要 #include<type_traits>
, #include<utility>
和 #include<cstddef>
):
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
return { {a[I]...} };
}
}
template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
关于另一个问题 - 关于排列,即当您寻找它的排列时,您希望您的集合找到 {1,2,3}
的迭代器。
从技术上讲,您可以做两件事:
(1) 制作一个专门的比较运算符,其排列是等价的。或者制作一个 class 包装 std::array
并以这种方式实现其比较运算符。
(2)(首选)在将数组添加到集 and/or 搜索之前简单地对数组进行排序。
如果您需要其元素的原始顺序,那么我建议制作实用程序 class,其中包含原始数组和用于比较的排序版本。
如果您还希望能够添加具有多个原件的选项,同时在它存在时返回确切的原件...那么它会更复杂。可以用一些复合函数来完成。
正如@walnut 所说,您不能在 class 定义之外为 class 的成员函数声明额外的重载。除了封装您自己的 int<3> class,还有另一种解决方法 - operator << override.
set<array<int, 3>>& operator << (set<array<int, 3>>& s, int ar[3])
{
array<int,3> ar2 { ar[0], ar[1], ar[2] };
s.insert(ar2);
return s;
}
看起来很奇怪,但是很好用。
现在你可以做到了
set<array<int, 3>> s;
int ar[3] = {1,2,3};
s << ar;
但是,如果你想在 set against int[3] against array 中使用一堆函数,最好定义你自己的 class / struct。
template <class T, int arsize>
struct MyFixedArray
{
T ar[arsize];
MyFixedArray(T _ar[arsize]) {
for (int i = 0; i < arsize; ++i)
ar[i] = _ar[i];
};
operator array<T, arsize>() const {
array<T, arsize> _ar;
for (int i = 0; i < arsize; ++i)
_ar[i] = ar[i];
return _ar;
};
};
现在您可以随时随地自由使用它
MyFixedArray<int, 3> myar(ar);
s.insert(myar);
auto it = s.find(myar);
我有这样的代码:
set<array<int, 3>> s;
int ar[3] = {1,2,3};
s.insert(ar);
auto it = s.find(ar);
以及 IDE 的消息 no instance of overloaded function insert/find
。如果我使用 std::array
没问题,::insert
和 ::find
的工作方式相同。
但是,如果我想使用这些 C 数组 T[N]
或在 set should return 迭代器中查找带有 std::array
的函数,如果三个元素中的两个相等。或者 set::insert
不会插入新数组,如果它是存在的排列,我的意思是 s.insert({1,2,3})
- 已经添加,s.insert({3,2,1})
- return {1,2,3}
上的迭代器。
问题是如何重载STD函数?不是在这段代码中,而是在一般情况下?欢迎任何 link 或真实代码示例。对于有经验的程序员来说,这可能是一个非常简单的问题)但是有很多运算符重载的例子,但对于 STL 却没有。谢谢。
我不认为 C++ 赋予您这样做的权利。有关更多信息,您可能会得到这个 answer 对您的情况有用。 希望对您的问题有所帮助。
您不能在 class 定义之外为 class 的成员函数声明额外的重载。该语言不为其提供语法。由于您无法修改标准库 headers 中的 class 定义,因此您也无法为其添加额外的重载。
std
命名空间中的自由函数不能被重载。它有语法(与任何自由函数重载的工作方式相同),但这样做会导致未定义的行为,因为它在标准中被明确禁止,请参见 [namespace.std]/1.
通常(有例外)允许的是为 std
命名空间中的实体定义 模板特化 ,但前提是该特化依赖于 user-defined 类型,不适用于成员函数、成员函数模板或成员 class 模板。请参阅上面链接的引用和后续段落的其余部分。
使用 std
命名空间内部特化的常见示例是 std::hash
用作无序关联容器中的哈希函数:
struct my_type {
//...
};
namespace std {
template<>
struct hash<my_type> {
auto operator()(my_type const& x) const noexcept {
//...
}
};
}
但是,如果 my_type
被 int*
、int[3]
或 std::array<int, 3>
或类似的任何东西替换,即使是这样的东西也是不允许的,因为不依赖于user-declared类型。
如果您想从 built-in 数组创建 std::array
,您将能够在 C++20 中使用 std::to_array
:
set<array<int, 3>> s;
int ar[3] = {1,2,3};
s.insert(std::to_array(ar));
auto it = s.find(std::to_array(ar));
在 C++20 之前,您可以在 #include<experimental/array>
中将函数作为 std::experimental::to_array
提供,或者您可以自己定义它(来自 cppreference.com;需要 #include<type_traits>
, #include<utility>
和 #include<cstddef>
):
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
return { {a[I]...} };
}
}
template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
关于另一个问题 - 关于排列,即当您寻找它的排列时,您希望您的集合找到 {1,2,3}
的迭代器。
从技术上讲,您可以做两件事:
(1) 制作一个专门的比较运算符,其排列是等价的。或者制作一个 class 包装 std::array
并以这种方式实现其比较运算符。
(2)(首选)在将数组添加到集 and/or 搜索之前简单地对数组进行排序。
如果您需要其元素的原始顺序,那么我建议制作实用程序 class,其中包含原始数组和用于比较的排序版本。
如果您还希望能够添加具有多个原件的选项,同时在它存在时返回确切的原件...那么它会更复杂。可以用一些复合函数来完成。
正如@walnut 所说,您不能在 class 定义之外为 class 的成员函数声明额外的重载。除了封装您自己的 int<3> class,还有另一种解决方法 - operator << override.
set<array<int, 3>>& operator << (set<array<int, 3>>& s, int ar[3])
{
array<int,3> ar2 { ar[0], ar[1], ar[2] };
s.insert(ar2);
return s;
}
看起来很奇怪,但是很好用。
现在你可以做到了
set<array<int, 3>> s;
int ar[3] = {1,2,3};
s << ar;
但是,如果你想在 set against int[3] against array 中使用一堆函数,最好定义你自己的 class / struct。
template <class T, int arsize>
struct MyFixedArray
{
T ar[arsize];
MyFixedArray(T _ar[arsize]) {
for (int i = 0; i < arsize; ++i)
ar[i] = _ar[i];
};
operator array<T, arsize>() const {
array<T, arsize> _ar;
for (int i = 0; i < arsize; ++i)
_ar[i] = ar[i];
return _ar;
};
};
现在您可以随时随地自由使用它
MyFixedArray<int, 3> myar(ar);
s.insert(myar);
auto it = s.find(myar);