C++11标准中,map的at()常量访问器是否是标准?

8
我试图找出如何从const方法返回map中的值,并偶然发现了gcc 4.6中map的at()方法。

当我查找此内容时,我意识到它是非标准的:

C++ map access discards qualifiers (const)

但它确实比find()方法更简洁。我想知道C++11是否已经纠正了这个问题 - at()方法是否为map的一部分?
1个回答

17

是的。在C++11中,std::map有一个at成员函数,其规格如下(23.4.4.3/9):

T&       at(const key_type& x);
const T& at(const key_type& x) const;

返回值:返回与x对应的*this中的mapped_type的引用。

抛出异常:如果不存在这样的元素,则抛出类型为out_of_range的异常对象。

复杂度:对数级别。

需要注意的是,该成员函数是专门添加到std::map中的。它不是更一般的关联容器要求所必需的。如果您正在编写需要某些关联容器类型的通用代码,则无法使用此新的at。相反,您应该继续使用关联容器概念的一部分的find,或者编写自己的非成员帮助程序:

template <typename AssociativeContainer>
typename AssociativeContainer::mapped_type&
get_mapped_value(AssociativeContainer&                          container,
                 typename AssociativeContainer::key_type const& key)
{
    typename AssociativeContainer::iterator it(container.find(key));
    return it != container.end() ? it->second : throw std::out_of_range("key");
}

template <typename AssociativeContainer>
typename AssociativeContainer::mapped_type const&
get_mapped_value(AssociativeContainer const&                    container,
                 typename AssociativeContainer::key_type const& key)
{
    typename AssociativeContainer::const_iterator it(container.find(key));
    return it != container.end() ? it->second : throw std::out_of_range("key");
}

如果你有一个支持右值引用和 decltype 的实现,你就不需要两个重载函数:

template <typename AssociativeContainer, typename Key>
auto get_mapped_value(AssociativeContainer&& container, Key const& key)
    -> decltype(std::declval<AssociativeContainer>().begin()->second)&
{
    auto const it(container.find(key));
    return it != container.end() ? it->second : throw std::out_of_range("key");
}

(或类似的内容;C ++ 11的有趣之处在于,没有两个编译器有相同的错误,并且所有编译器似乎都接受略微不同的有效 - 和无效的 - C ++ 11代码子集。)


我认为所有的编译器都在接近C++11的标准,但这可能是我的乐观之心 :) - Matthieu M.
1
“nitpick”。“at”方法不仅被添加到std::map中,也被添加到std::unordered_map中。这是唯一真正有意义的两个标准容器。此外,您的代码不仅适用于AssociateveContainers,还适用于UnorderedAssociateveContainers,除了set和unordered_set之外,而且对于multimap和unordered_multimap来说几乎没有意义。 - Konstantin Oznobihin
@Konstantin:是的,也许UniqueAssociativeContainer会是一个更好的模板参数名称(UniqueAssociativeContainerOrUniqueUnorderedAssociativeContainer太笨重了:-O)。关键是有些容器满足容器概念的要求,而且应该在通用代码中与C++标准库容器互换使用。依赖新的at的代码无法利用这些其他容器。 - James McNellis
@Matthieu:我不知道...Visual C++ 2010接受了这个答案中的代码,但我无法打败g++ 4.6。我有一个相当大的业余代码库,使用了C++0x功能;它可以在Visual C++中编译,但由于两个错误(一个涉及在类模板中捕获lambda,另一个涉及模板实例化失败),我无法使用g++编译它,或者clang(它根本不支持lambda)。 - James McNellis
@James 我使用了许多 C++11 特性(lambda 表达式,基于范围的 for 循环,at(),auto),在 OSX 上使用 g++-mp-4.6,并且它的表现非常出色,目前为止都没有问题,使用 -std=c++0x 参数。使用 LLVM 就没那么顺利了(暂时没时间研究如何将 libc++ 与其配合使用)。 - daj
显示剩余2条评论

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