这个C ++示例是可移植的吗?

时间:2013-09-12 15:01:31

标签: c++ visual-studio-2010 stl

this问题之后,我尝试复制粘贴在VS2010中找到的here示例:

#include <algorithm>
#include <vector>
#include <iostream>

struct S
{
    int number;
    char name;

    S ( int number, char name  )
        : number ( number ), name ( name )
    {}

    // only the number is relevant with this comparison
    bool operator< ( const S& s ) const
    {
        return number < s.number;
    }
};

struct Comp
{
    bool operator() ( const S& s, int i )
    {
        return s.number < i;
    }

    bool operator() ( int i, const S& s )
    {
        return i < s.number;
    }
};

int main()
{
    std::vector<S> vec = { {1,'A'}, {2,'B'}, {2,'C'}, {2,'D'}, {3,'F'}, {4,'G'} }; //this syntax won't compile in VS2010, so you can leave an empty vector here

    auto p = std::equal_range(vec.begin(),vec.end(),2,Comp());

    for ( auto i = p.first; i != p.second; ++i )
        std::cout << i->name << ' ';
}

这将在发布模式下正常编译,但在调试模式下,它将无法编译。 原因是在调试模式下,实现将使用给定的谓词检查迭代器范围是否已经排序:

template<class _FwdIt,
    class _Pr> inline
    void _Debug_order2(_FwdIt _First, _FwdIt _Last, _Pr _Pred,
        _Dbfile_t _File, _Dbline_t _Line, forward_iterator_tag)
    {   // test if range is ordered by predicate, forward iterators
    for (_FwdIt _Next = _First; _First != _Last && ++_Next != _Last; ++_First)
        if (_DEBUG_LT_PRED(_Pred, *_Next, *_First))
            _DEBUG_ERROR2("sequence not ordered", _File, _Line);
    }

这最终要求:

template<class _Pr, class _Ty1, class _Ty2> inline
    bool _Debug_lt_pred(_Pr _Pred,
        const _Ty1& _Left, const _Ty2& _Right,
        _Dbfile_t _File, _Dbline_t _Line)
    {   // test if _Pred(_Left, _Right) and _Pred is strict weak ordering
    if (!_Pred(_Left, _Right))
        return (false);
    else if (_Pred(_Right, _Left))
        _DEBUG_ERROR2("invalid operator<", _File, _Line);
    return (true);
    }

除了在我的情况下,没有operator()可以同时采用左和右“S”参数。 那么,Visual实现中是否存在错误?或者原始的例子不应该是便携式的? 我想我可以通过提供第三个operator()重载来使它工作,但它似乎应该没有

感谢

5 个答案:

答案 0 :(得分:12)

标准中没有任何内容要求比较器可以使用范围内的两个对象进行调用。这是VS 2010使用的标准库中的一个错误。

以下是所有相关要求(引用C ++ 11):

[lower.bound]§1+ 2:

  

1 需要: e的元素[first,last)应根据表达式comp(e, value)进行分区。

     

2 返回: i范围内的最远迭代器[first,last],对于j范围内的任何迭代器[first,i),以下对应条件成立:...... comp(*j, value) != false

[upper.bound]§1+ 2:

  

1 需要: e的元素[first,last)应根据表达式!comp(value, e)进行分区。

     

2 返回: i范围内的最远迭代器[first,last],对于j范围内的任何迭代器[first,i),以下对应条件成立:...... comp(value, *j) == false

[equal.range]§1+ 2:

  

1 需要: e的元素[first,last)应根据表达式comp(e, value)!comp(value, e)进行分区。此外,对于e的所有元素[first, last),...... comp(e, value)应暗示!comp(value, e)

     

2 返回:

     

...

make_pair(lower_bound(first, last, value, comp),
          upper_bound(first, last, value, comp))

(省略号用于非比较器版本)。

答案 1 :(得分:2)

Angew已经引用了该标准,并指出VS有缺陷。我只想强调 VS2010有两个错误(在调试模式下):

  1. 它尝试使用标准不需要存在的Compare::operator(_Ty1, _Ty2)。这个known bug已被Angew强调并由Ben的评论指出。

  2. 它测试输入范围是否已排序,标准也不需要。 这是一个更严重的错误,因为它降低了equal_range的可用性,并且在最坏的情况下需要一个完整的范围,即使这在算法上是不必要的。也许有人可以向MS提交错误报告?

  3. 请注意,第一个错误只是第二个错误的结果(在equal_range的实现中)。据推测,对于大多数应用程序,输入范围已经排序,部分原因是用户对其进行了不必要的排序(证明MS库中的错误会导致用户代码错误),并且只需提供额外的比较运算符即可解决问题(至于OP的问题)。

答案 2 :(得分:1)

[lib.equal.range]告诉:

  

要求:类型T是LessThanComparable(20.1.2)。

  

效果:找到最大的子范围[i,j],使得该值可以   插入任何迭代器k而不违反排序。 ķ   满足相应的条件:!(* k <值)&amp;&amp; !(值&lt; * k)   或comp(* k,value)== false&amp;&amp; comp(value,* k)== false。

您的代码满足这两个条件并且编译得很好,这意味着它是visual studio中的一个错误。

答案 3 :(得分:1)

作为一般答案。每个编译器和标准库都会有一些怪癖和地方,它们没有正确实现标准。这意味着除非代码在不同的平台上进行测试,否则总是有可能需要进行微小的更改。

从好的方面来说,如果一个人试图保持标准,这些变化应该非常小。

答案 4 :(得分:-1)

为了使相等的范围正常工作,范围需要排序,我认为VS编译器试图说你的意图是错的,也许?