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

时间:2012-01-14 11:40:19

标签: c++ c++11 const

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

这些方面的东西:

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(显然)和提升。

提前致谢。

1 个答案:

答案 0 :(得分:3)

我认为你正在寻找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);
}

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