为什么在 map 上使用 std::for_each 会调用拷贝构造函数?

10

我有以下简单的示例,我想在一个不可复制的对象集合上调用std::for_each

class A {
public:
    A() : x(0) {}
    A(const A&) = delete;

private:
    int x;
};

void func() {
    std::vector<A> v(10);
    std::map<int, A> m;

    // works as expected
    std::for_each(begin(v), end(v), [](const A& a) { /* do nothing */ });

    // error calling copy constructor
    std::for_each(begin(m), end(m), [](const std::pair<int, A>& a) { /* do nothing */ });
}
如果我把所有东西都放进一个std::vector中,它就像我预期的那样工作,但是使用std::map时,突然std::for_each想要调用(已删除的)拷贝构造函数。为什么? 我原本以为只会获得保存在映射中的一对的引用,而不需要进行任何必要的副本。

@fschoenm,请查看链接中的答案或回答非常相似的问题。 - Hulk
谢谢,我的问题已经得到解答。我之前搜索的是“for_each”,而不是“foreach”,所以搜索引擎没有显示其他结果。 - fschoenm
1个回答

15
问题在于,std::mapstd::pair<const Key, Value> 作为其内部值类型。而标准库容器允许您从容器类型中提取该类型,而不是显式地指定它:
在 C++11 中执行(与 C++98 相同,但您必须在 for_each 内部使用函数对象而不是 lambda,并且还要使用 typedef 而不是 using=):
using value_type = std::map<int, A>::value_type;
std::for_each(begin(m), end(m), [](value_type const& a) { /* do nothing */ });

在C++14中,执行以下操作:

std::for_each(begin(m), end(m), [](auto const& a) { /* do nothing */ });

在Lambda内使用 auto 的功能受到 Clang 3.4、Visual Studio 2013年11月CTP和GCC 4.9的支持。


1
在C++03中使用Lambda可能有点勉强 :) 我认为您指的是C++11和C++1y。 - juanchopanza
谢谢!我知道“std::map”现在有一个常量键。我只是没有联系起来,而我的编译器的错误信息也不太有帮助。 - fschoenm
请注意,std::for_each(begin(m), end(m), [](std::pair<int, A const&> a) { /* do nothing */ }) 应该可以工作:将键复制,但使用值的引用。 - Yakk - Adam Nevraumont
@Yakk 没错,但对于通用代码来说,显式类型更冗长,复制+引用开销更大(例如,如果键是 std::string)。 - TemplateRex
有人能把表单中的错字“into”改成“from”吗? - Herbert
@Herbert 谢谢,已修复! - TemplateRex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接