这是一个最小的例子,它展示了两种获取迭代器类型的方法,我天真地期望得到相同的类型作为结果:
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 21: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
复制相似问题