有什么方法可以欺骗 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));
(1) - 它依赖于 std::iterator_traits
推导出正确的东西。如本例中所写,它可能不符合规定的迭代器类型的所有要求(在本例中,我们针对的是前向迭代器)。如果发生这种情况,将需要更多 boiler-plate。
所以我写了这段无法编译的代码。我认为原因是因为 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));
(1) - 它依赖于 std::iterator_traits
推导出正确的东西。如本例中所写,它可能不符合规定的迭代器类型的所有要求(在本例中,我们针对的是前向迭代器)。如果发生这种情况,将需要更多 boiler-plate。