简体   繁体   English

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

[英]is this C++ example portable?

following this question , I tried to copy paste the example found here in VS2010 : 下面的这个问题,我试图复制粘贴发现的例子在这里在VS2010:

#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 << ' ';
}

This will compile fine in release mode, but in debug mode, it will fail to compile. 这将在发布模式下正常编译,但在调试模式下,它将无法编译。 The reason is that in debug mode, the implementation will check if the iterator range is already sorted, using the given predicate: 原因是在调试模式下,实现将使用给定的谓词检查迭代器范围是否已经排序:

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);
    }

this ends up calling : 这最终要求:

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);
    }

Except that in my case, no operator() can take both left and right "S" argument. 除了在我的情况下,没有operator()可以同时采用左和右“S”参数。 So, is there a bug in the Visual implementation? 那么,Visual实现中是否存在错误? Or is the original example not supposed to be portable? 或者原始的例子不应该是便携式的? I think I could make it work by providing a 3rd operator() overload, but it seems like it should work without 我想我可以通过提供第三个operator()重载来使它工作,但它似乎应该没有

thanks 谢谢

Nothing in the standard requires the comparator to be callable with two objects from the range. 标准中没有任何内容要求比较器可以使用范围内的两个对象进行调用。 So that is a bug in the standard library used by VS 2010. 这是VS 2010使用的标准库中的一个错误。

Here are all the relevant requirements (quoting C++11): 以下是所有相关要求(引用C ++ 11):

[lower.bound]§1+2: [lower.bound]§1+ 2:

1 Requires: The elements e of [first,last) shall be partitioned with respect to the expression ... comp(e, value) . 1 要求: [first,last)的元素e应根据表达式... comp(e, value)进行分区。

2 Returns: The furthermost iterator i in the range [first,last] such that for any iterator j in the range [first,i) the following corresponding conditions hold: ... comp(*j, value) != false . 2 返回: [first,last]范围内的最远迭代器i ,使得对于[first,i)范围内的任何迭代器j ,以下相应条件成立:... comp(*j, value) != false

[upper.bound]§1+2: [upper.bound]§1+ 2:

1 Requires: The elements e of [first,last) shall be partitioned with respect to the expression ... !comp(value, e) . 1 要求: [first,last)的元素e应根据表达式... !comp(value, e)进行分区。

2 Returns: The furthermost iterator i in the range [first,last] such that for any iterator j in the range [first,i) the following corresponding conditions hold: ... comp(value, *j) == false . 2 返回:最远迭代i在范围[first,last] ,使得对于任何迭代j范围[first,i)下列相应条件成立:... comp(value, *j) == false

[equal.range]§1+2: [equal.range]§1+ 2:

1 Requires: The elements e of [first,last) shall be partitioned with respect to the expressions ... comp(e, value) and !comp(value, e) . 1 要求: [first,last)的元素e应根据表达式... comp(e, value)!comp(value, e)进行分区。 Also, for all elements e of [first, last) , ... comp(e, value) shall imply !comp(value, e) . 此外,对于[first, last)所有元素e ,... comp(e, value)应表示!comp(value, e)

2 Returns: 2 返回:

... ...

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

(The ellipses are for the non-comparator version). (省略号用于非比较器版本)。

Angew has already quoted the standard and pointed out that VS is buggy. Angew已经引用了该标准,并指出VS有缺陷。 I merely want to emphasize that VS2010 has two bugs here (under debug mode): 我只是想强调VS2010在这里有两个错误 (在调试模式下):

  1. It tries to use Compare::operator(_Ty1, _Ty2) which is not required to exist by the standard. 它尝试使用Compare::operator(_Ty1, _Ty2) ,该标准不需要存在。 This known bug has been highlighted by Angew and pointed to by Ben's comment. 这个已知的错误已被Angew强调并由Ben的评论指出。

  2. It tests whether the input range is sorted, which is not required by the standard either. 它测试输入范围是否已排序,标准也不需要。 This is a far more serious bug, as it reduces the usability of equal_range and in the worst case requires a full sort of the range, even if that was not necessary algorithmicly. 这是一个更严重的错误,因为它降低了equal_range的可用性,并且在最坏的情况下需要一个完整的范围,即使这在算法上是不必要的。 Perhaps somebody can file a bug report to MS? 也许有人可以向MS提交错误报告?

Note that the first bug is merely a consequence (in the implementation of equal_range ) of the second bug. 请注意,第一个错误仅仅是第二个错误的结果(在equal_range的实现中)。 Presumably, for most applications the input range is already sorted, partly because the user sorted it unnecessarily (demonstrating that bugs in MS's library results in bad user code), and simply providing an additional comparison operator fixes the problem (as for the OPs' question). 据推测,对于大多数应用程序,输入范围已经排序,部分原因是用户不必要地对其进行排序 (证明MS库中的错误导致错误的用户代码),并且只是提供额外的比较运算符来解决问题(就OP的问题而言) )。

[lib.equal.range] tells : [lib.equal.range]告诉:

Requires: Type T is LessThanComparable (20.1.2). 要求:类型T是LessThanComparable(20.1.2)。

and

Effects: Finds the largest subrange [i, j) such that the value can be inserted at any iterator k in it without violating the ordering. 效果:查找最大的子范围[i,j],使得值可以插入其中的任何迭代器k而不违反排序。 k satisfies the corresponding conditions: !(*k < value) && !(value < *k) or comp(*k, value) == false && comp(value, *k) == false. k满足相应的条件:!(* k <value)&&!(value <* k)或comp(* k,value)== false && comp(value,* k)== false。

Your code satisfies both conditions and should compile fine, meaning it is a bug in visual studio. 您的代码满足这两个条件并且编译得很好,这意味着它是visual studio中的一个错误。

As a General Answer. 作为一般答案。 Each compiler and standard library will have quirks and places that they do not implement the standard properly. 每个编译器和标准库都会有一些怪癖和地方,它们没有正确实现标准。 Which means that unless the code is tested on a different platform, there is always a chance that minor changes will be required. 这意味着除非代码在不同的平台上进行测试,否则总是有可能需要进行微小的更改。

On the plus side, if one uses an attempt to keep to the standard, these changes should be very minor. 从好的方面来说,如果一个人试图保持标准,那么这些变化应该非常小。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM