【问题标题】:Operator overloading and iterator confusion运算符重载和迭代器混淆
【发布时间】:2013-09-07 06:12:43
【问题描述】:

我使用这个代码来找到一个盒子的点 (g) 在方向上最远 d typedef vector_t point_t;

std::vector<point_t> corners = g.getAllCorners();
coordinate_type last_val = 0;

std::vector<point_t>::const_iterator it = corners.begin();
point_t last_max = *it;

do
{
    coordinate_type new_val = dot_product( *it, d );
    if( new_val > last_val )
    {
        last_val = new_val;
        last_max = *it;
    }
}
while( it != corners.end() );

return last_max;

对于vector_t 的类vector_t 的运算符!=,我还有一个模板运算符重载,它位于命名空间point 中。

namespace point
{
    template 
    <
        typename lhs_vector3d_impl, 
        typename rhs_vector3d_impl
    >
    bool operator!=( const typename lhs_vector3d_impl& lhs, const typename rhs_vector3d_impl& rhs )
    {
        return binary_operator_not_equal<lhs_vector3d_impl, rhs_vector3d_impl>::apply( lhs, rhs );
    }
};

重载在大多数情况下都可以正常工作,但是当我使用迭代器(即it != corners.end())时,它会崩溃,因为在这种情况下我不打算使用此函数。 我可以说这是因为模板参数解析出错但我不知道为什么:

lhs_vector3d_impl=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<legend::geometry::point::Carray_Vector3d<int32_t>>>>,
rhs_vector3d_impl=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<legend::geometry::point::Carray_Vector3d<int32_t>>>>

我知道调用了错误的函数,但我不明白为什么……

所以基本上我的问题是如何用我的函数而不是 std 命名空间中的运算符解决 comme 迭代器比较,以及如何防止使用此函数。

注意1:我是从模板开始的,所以我可能在不知不觉中做错了什么,如果是,请告诉。

注意 2:此代码主要用于学术目的,所以我真的很想手动完成大部分工作。

注意 3:使用 Visual Studio 2012 C++ 编译器

【问题讨论】:

  • (A) 你可能写了using namespace point 所以一切都看到了过载。 (B) 重载是template&lt;class A, class B&gt; bool operator(const A&amp;,const B&amp;),它匹配所有类型。不要在这里使用模板。有一些变通方法,但它们令人困惑。
  • 即使没有using namespace,它也会通过 ADL 的魔力被拾取 - 这不是你想要的。

标签: c++ templates stl iterator operator-overloading


【解决方案1】:

如果你真的需要重载运算符 != 像它一样通用,那就是采用 any 两个参数,即匹配你传递给它的几乎所有东西,你可以避免它被首选用于通过显式调用标准库版本的迭代器:

std::operator !=(it, corners.end())

【讨论】:

    【解决方案2】:

    我不明白你为什么需要这个模板功能。 但很明显,当您只想将它​​用于point_t时,它可能已经推断出lhs和rhs类型是iterator

    两种解决方案:

    1. 删除运算符定义上的模板并使用 point_t 作为类型(所以你确定)
    2. 删除 using 命名空间以确保他看到 namespace point 之外的迭代器

    【讨论】:

    • 取消引用 end() 是未定义的行为。
    • @dzada 不应该调用默认迭代器比较而不是我的“比较值”运算符吗?
    • 不,不应调用默认版本,因为您明确定义了一个完全符合要求的函数(尽管是模板化的)。在我看来,您的模板定义太宽泛了,它基本上覆盖了 any 默认operator!=
    • @cmaster 但是对于用户定义的对象,比如这些迭代器,没有 default operator !=。尽管标准库提供了对其迭代器进行操作的重载,但只要它们特定于它们的类型,就不会发生运算符阴影。我不确定标准需要什么作为默认行为以及 MSVC 是否符合它,但 GCC 4.8.1 选择正确的版本没有问题,即使发出 using namespace std; 也是如此。作为 MSVC 的解决方法,请参考我的回答。
    • @brunocodutra 通常,迭代器是某些指针类型的类型定义(否则它们会非常慢),并且编译器知道如何比较指针。也许,还有一些迭代器是对象,在这些情况下你是对的,但对于大多数人来说,这个定义确实会影响默认运算符。
    猜你喜欢
    • 2011-10-18
    • 2016-02-03
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多