重载 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_typeint*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);