这是一个最小的例子,它展示了两种获取迭代器类型的方法,我天真地期望得到相同的类型作为结果:
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;
}
但这实际上触发了静态断言。
如果我们将第一个迭代器更改为:
using iterator = decltype(std::declval<Range>().begin());
没有触发静态断言。
查看std::begin()
的定义,这对于引用和常量引用类型都是重载的。由于declval
返回一个右值引用,这将只绑定到常量引用,从而返回常量迭代器类型。
这可以解决一些令人厌恶的事情,使用引用折叠:
using iterator = decltype(std::begin(std::declval<typename std::add_lvalue_reference<Range>::type>()));
有没有更简单的方法来获得一个非常量迭代器?显然,typename Range::iterator
不会存在于所有类型(例如T*
)中,对于成员begin()
也是如此,因此两者都不是理想的。
发布于 2018-06-18 13:29:32
直接调用std::begin
甚至不是获得begin迭代器的正确方式。正确的习惯用法需要两个语句:using std::begin; begin(rng);
。这显然不能在decltype
中实现。
这样做对于没有成员begin
/end
或std::begin/end
重载的类型是不起作用的。
因此,正确的解决方案是创建一个执行此操作的函数:
template<typename Range>
auto my_begin(Range &&rng)
{
using std::begin;
return begin(std::forward<Range>(rng));
}
然后在decltype
字段中调用该函数。
https://stackoverflow.com/questions/50905808
复制相似问题