迭代器和无符号整数的重载+运算符

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器和无符号整数的重载+运算符相关的知识,希望对你有一定的参考价值。

我正在尝试重载+运算符以获取列表迭代器和无符号整数(用于实践)。下面的代码似乎工作正常。解释它应该做什么:如果iter是迭代器而k是无符号整数,那么iter+k(或operator+(iter, k))返回从递增iter k次获得的迭代器。

list<int>::iterator operator+(list<int>::iterator iter, unsigned k)
{
    while (k != 0)
    {
        ++iter;
        --k;
    }
    return iter;
}

但是,当我这样做时:

template<typename T>
typename list<T>::iterator 
operator+(typename list<T>::iterator iter, unsigned k)
{
    while (k != 0)
    {
        ++iter;
        --k;
    }
    return iter;
}

并运行简单的事情

int main(){
    list<int> l{1,2};
    list<int>::iterator q = l.begin();
    q+1;
}

我收到一个我无法破译的大错误。我也试过无济于事:

int main(){
    list<int> l{1,2};
    list<int>::iterator q = l.begin();
    operator+<int>(q,1);
}

关于为什么会发生这种情况以及如何解决这个问题的任何想法都将非常感谢!

答案

问题是模板类型参数Tnon-deduced context中,无法推导出来。为了使其可以推导,你可以这样做:

template<typename T>
T operator+(T iter, unsigned k)
{ ... }

请注意,这种重载可能会造成很大的伤害,因为T并不局限于std::list<T>::iterator。 SFINAE可以提供帮助:

template<typename T, typename = std::enable_if_t<
    std::is_same_v<T, typename std::list<
    typename std::iterator_traits<T>::value_type>::iterator>>>
T operator+(T iter, unsigned k)
{ ... }

加成。

operator+<int>(q, 1);失败的问题更为微妙。首先,引用标准,[temp.arg.explicit] / 8(另见一个例子):

但是当使用带有显式模板参数的函数模板时,除非在调用点处有一个具有该名称的函数模板,否则调用没有正确的语法形式。如果看不到这样的名称,则调用语法不完善,并且参数依赖查找不适用。如果某些此类名称可见,则应用依赖于参数的查找,并且可以在其他名称空间中找到其他函数模板。

我们这里有这样一个功能模板,它是我们的operator+。因此,ADL试图在operator+<int>找到std::。但是,当使用operator+实例化某些<int>模板时,编译失败。哪一个以及它如何失败,取决于特定的std库实现。

例如,gcc 8.1尝试实例化

template<class _Iterator> constexpr 
std::move_iterator<_IteratorL> std::operator+(
   typename std::move_iterator<_IteratorL>::difference_type,
   const std::move_iterator<_IteratorL>&)
[with _Iterator = int]

并在里面失败了

error: no type named 'reference' in 'struct std::iterator_traits<int>'
...

如果我们禁用ADL,它将按预期工作:

::operator+<int>(q, 1);

要么

(operator+<int>)(q, 1);
另一答案

这与C ++模板类型推导的工作方式有关。由于语言的设置方式,编译器无法在list<T>::iterator的上下文中推断出应该自动生成的内容。原因在于,由于模板特化,理论上可能两个不同的list实例可以具有相同的嵌套iterator类型(例如,list<Pizwkat>list<Swibble>),在这种情况下编译器将无法确定是否应该是PizkwatSwibble,因为两种选择都可能合理。

我不相信有一个简单的解决方案来解决“添加一个仅适用于列表迭代器的operator +”的一般问题,尽管你可以考虑使用std::nextstd::advance函数,它们适用于所有类型的迭代器。 (作为一个注释,为库类型添加自定义重载通常不是一个好主意,所以即使你可以这样做,它可能不是你想要解决的任何问题的最佳解决方案。)

以上是关于迭代器和无符号整数的重载+运算符的主要内容,如果未能解决你的问题,请参考以下文章

ECMAScript5运算符

类型匹配没有可行的重载运算符

如何忽略“有符号和无符号整数表达式之间的比较”?

C++ [ ] 索引运算符重载为访问器和修改器

有符号和无符号数据类型

python 10 迭代器和三元运算符