有什么方法可以欺骗 std::transform 对迭代器本身进行操作?

Any way to trick std::transform into operating on the iterator themselves?

所以我写了这段无法编译的代码。我认为原因是因为 std::transform,当给定一个像这样的迭代器范围时,它将对迭代器指向的类型进行操作,而不是迭代器本身。是否有任何简单的包装器、标准 lib 工具等来使此代码正常工作,即将原始地图的所有迭代器存储到一个新向量中,而所需的更改最少?谢谢!

#include <map>
#include <iostream>
#include <vector>

using MT = std::multimap<char, int>;
using MTI = MT::iterator;

int main()
{
    MT m;
    m.emplace('a', 1); m.emplace('a', 2); m.emplace('a', 3);
    m.emplace('b', 101);
        
    std::vector<MTI> itrs;
    std::transform(m.begin(), m.end(), std::back_inserter(itrs), [](MTI itr){
        return itr;
    });
}

编辑 1:无法使用 gcc11 和 clang13、C++17/20 进行编译

编辑 2:问题的目的主要是出于好奇。我想看看什么是操纵现有标准算法以达到我想要的水平的好方法。示例代码和问题完全是为了演示而编造的,但它们与任何需要解决方案的实际问题无关

您传递给 std::transform 的函数和一般算法应该使用元素而不是迭代器。您可以使用键在映射中查找迭代器,但这既不高效也不简单。而是使用普通循环:

for (auto it = m.begin(); it != m.end(); ++it) itrs.push_back(it);

有这样的包装器吗?不在标准范围内。但这并不意味着你不能写一个,甚至相当简单。

template<typename It>
struct PassIt : It {
    It& operator*()              { return *this; }
    It const& operator*() const  { return *this; }
    PassIt & operator++()        { ++static_cast<It&>(*this); return *this; }
    PassIt operator++(int) const { return PassIt{static_cast<It&>(*this)++}; }
};

template<typename It>
PassIt(It) -> PassIt<It>;

这只是包装器的一个示例1,它是指定模板参数类型的迭代器。它委托其基础进行簿记,同时确保 return 类型在取消引用时符合 return 包装的迭代器本身。

您可以在示例中使用它来简单地复制迭代器

std::copy(PassIt{m.begin()}, PassIt{m.end()}, std::back_inserter(itrs));

See it live


(1) - 它依赖于 std::iterator_traits 推导出正确的东西。如本例中所写,它可能不符合规定的迭代器类型的所有要求(在本例中,我们针对的是前向迭代器)。如果发生这种情况,将需要更多 boiler-plate。