我需要一个泛型函数,它可以对容器进行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(显然)和提升。
提前致谢。
答案 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);
}
现在结果将移至s
。 enable_if
部分是必要的,因为由于引用了折叠规则,C&&
也可以绑定到左值,然后初始化s
的调用将是不明确的。