首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用declval获取非常量迭代器

使用declval获取非常量迭代器
EN

Stack Overflow用户
提问于 2018-06-18 16:53:41
回答 1查看 273关注 0票数 4

这是一个最小的例子,它展示了两种获取迭代器类型的方法,我天真地期望得到相同的类型作为结果:

代码语言:javascript
运行
复制
template <typename Range>
struct foo
{
    using iterator = decltype(std::begin(std::declval<Range>()));
    using iterator2 = typename Range::iterator;

    static_assert(std::is_same<iterator, iterator2>::value, "Iterator types differ!");
};

int main()
{
    std::vector<int> v;
    foo<decltype(v)> f;
}

但这实际上触发了静态断言。

如果我们将第一个迭代器更改为:

代码语言:javascript
运行
复制
using iterator = decltype(std::declval<Range>().begin());

没有触发静态断言。

查看std::begin()的定义,这对于引用和常量引用类型都是重载的。由于declval返回一个右值引用,这将只绑定到常量引用,从而返回常量迭代器类型。

这可以解决一些令人厌恶的事情,使用引用折叠:

代码语言:javascript
运行
复制
using iterator = decltype(std::begin(std::declval<typename std::add_lvalue_reference<Range>::type>()));

有没有更简单的方法来获得一个非常量迭代器?显然,typename Range::iterator不会存在于所有类型(例如T*)中,对于成员begin()也是如此,因此两者都不是理想的。

EN

回答 1

Stack Overflow用户

发布于 2018-06-18 21:29:32

直接调用std::begin甚至不是获得begin迭代器的正确方式。正确的习惯用法需要两个语句:using std::begin; begin(rng);。这显然不能在decltype中实现。

这样做对于没有成员begin/endstd::begin/end重载的类型是不起作用的。

因此,正确的解决方案是创建一个执行此操作的函数:

代码语言:javascript
运行
复制
template<typename Range>
auto my_begin(Range &&rng)
{
  using std::begin;
  return begin(std::forward<Range>(rng));
}

然后在decltype字段中调用该函数。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50905808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档