从容器中获取元素常量限定的通用方法

Generic way of getting const-qualification of elements from container

本文关键字:方法 常量 获取 元素      更新时间:2023-10-16

我需要一个泛型函数,它可以对容器进行常量或非常量引用,并返回对根据容器限定的元素的相应引用。

大致如下:

template <typename C>
auto get_nth( C& c, int i ) -> /* not-sure-what, but let's call it T */
{
      //.... some tricky code here ...
}

我想强调的是,如果C扩展到

SomeContainer const

那么T就是

SomeContainer::const_reference

以及其他

SomeContainer::reference

我想我可以用类型特征和mtl把它放在一起,如果,我的问题是是否有一种更短、更干净的方法。

我使用的是C++x11(显然)和boost。

提前谢谢。

我认为您正在寻找typename C::reference,请参阅23.2.1[container.requirements.general]§4。


哦,等等,如果C已经是const,那么上面的内容就不起作用了。但等一下,decltype来救援!

template <typename C>
auto get_nth( C&& c, int i ) -> decltype(*c.begin())
{
      //.... some tricky code here ...
}

如果您还想支持没有begin成员函数的C样式数组:

#include <iterator>
template <typename C>
auto get_nth( C&& c, int i ) -> decltype(*std::begin(c))
{
      //.... some tricky code here ...
}

而且实现真的不是那么棘手:

#include <iterator>
template <typename C>
auto get_nth( C&& c, int i ) -> decltype(*std::begin(c))
{
    auto it = std::begin(c);
    std::advance(it, i);
    return *it;
}

注意,上面的解决方案接受左值和右值,但它将始终返回一个左值引用。根据客户端代码的不同,这可能是一个性能问题。以以下代码为例:

std::string s = get_nth(std::vector<std::string> { "hello", "world" }, 0);

这将把结果复制到s中,即使移动它是完全有效的(当然,速度更快)。

为了解决这个问题,我们需要两个重载,一个用于左值,另一个用于右值:

#include <iterator>
#include <type_traits>
template <typename C>
auto get_nth( C& c, int i ) -> decltype(*std::begin(c))
{
    auto it = std::begin(c);
    std::advance(it, i);
    return *it;
}
template <typename C>
auto get_nth( C&& c, int i )
-> typename std::enable_if<std::is_rvalue_reference<C&&>::value,
                           decltype(std::move(*std::begin(c)))>::type
{
    auto it = std::begin(c);
    std::advance(it, i);
    return std::move(*it);
}

现在,结果将移动到s中。enable_if部分是必要的,因为由于引用折叠规则,C&&也可以绑定到lvalues,然后初始化s的调用将是不明确的。