有什么方法可以欺骗 std::transform 自己在迭代器上操作吗?

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

提问人:resnet 提问时间:1/27/2022 最后编辑:resnet 更新时间:1/28/2022 访问量:741

问:

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

#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:这个问题的目的主要是出于好奇。我想看看有什么好方法可以操纵现有的标准算法,使其在我想要的水平上工作。示例代码和问题完全是为了演示而编造的,但它们与任何需要解决方案的实际问题无关

C++ 迭代器 std

评论

2赞 Some programmer dude 1/27/2022
你到底想做什么?原始和潜在的问题是什么(如果有的话,简单的好奇心也可以,但请在问题本身中说明)?现在,这感觉很像一个XY问题
3赞 molbdnilo 1/27/2022
存储迭代器以备后用几乎总是一个错误。它们是暂时的。
0赞 resnet 1/28/2022
@Someprogrammerdude感谢您的评论,我会在问题中更清楚地说明
0赞 c z 7/14/2023
@molbdnilo 回复:存储迭代器以备后用几乎总是一个错误。源?从标准来看:“迭代器是指针的泛化”,我没有看到任何证据表明迭代器无效,除非基础集合发生更改或其生存期结束(即使如此,似乎也做出了具体的保证,具体取决于集合)。只有输出迭代器的写入操作 () 似乎会导致无效(当然这会更改集合)。*r = o

答:

0赞 463035818_is_not_an_ai 1/27/2022 #1

您传递给的函数和算法通常应该使用元素而不是迭代器。您可以使用该键在地图中查找迭代器,尽管这既不高效也不简单。请改用普通循环:std::transform

for (auto it = m.begin(); it != m.end(); ++it) itrs.push_back(it);
2赞 StoryTeller - Unslander Monica 1/27/2022 #2

有这样的包装器吗?不在标准中。但这并不意味着你不能写一个,即使是相当简单的。

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,它是指定模板参数类型的迭代器。它委托给其基础进行记账,同时确保返回类型符合在取消引用时返回包装迭代器本身。

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

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

现场观看


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

评论

0赞 resnet 1/28/2022
谢谢你,正是我正在寻找的那种答案。欣赏完整的模板演示
0赞 jian 2/26/2022
嗨,实时链接已损坏。我不知道如何坚持到底。以下代码不起作用。godbolt.org/z/cTxs8MhzT 您介意分享完整的代码。
0赞 StoryTeller - Unslander Monica 2/26/2022
@Mark - 坏了,怎么坏的?它把我带到这个例子,并吐出预期的输出。你的示例不起作用,因为你尝试将迭代器插入到整数向量中。将您的代码与 OP 进行比较。
0赞 jian 2/26/2022
@StoryTeller-UnslanderMonica:我猜网站已经关闭了。无论如何,谢谢......