c++visual-studio-2008functorupperboundcommutativity

upper_bound With binary_function Visual Studio 2008 Bug?


1st of all, yes, I am stuck using Visual Studio 2008, and I believe this bug is specific to Visual Studio 2008.

I'm trying to write a functor to compare just 1 member of my struct so I can do upper_bound on a vector of said structs which is sorted by that member. That's hard to explain in words so here's an example:

struct Foo {
    int a;
    char b;
};

struct comp : binary_function<const double, const Foo&, bool> {
    bool operator () (const double lhs, const Foo& rhs) { return lhs < rhs.a; }
};

int main() {
    vector<Foo> test;

    for(int i = 0; i < 5; ++i) {
        Foo foo = { i + 1, 'a' + i };

        test.push_back(foo);
    }

    cout << upper_bound(test.begin(), test.end(), 2, comp())->b << endl;
}

This works fine on Visual Studio 2015. But Visual Studio 2008 gives me the error:

error C2664: 'bool comp::operator ()(const double,const Foo &)' : cannot convert parameter 1 from 'Foo' to 'const double'

I suspect that there is some evil in the implementation where the functor is tested for strict weak ordering by swapping the inputs. Is there a workaround to suspend that checking on the compiler, or do I just have to just change my functor to taking in 2 Foos and make a temporary Foo to represent the 2 here?


Solution

  • As stated by Algirdas Preidžius this is a Debug only implementation error in Visual Studio 2008. It has been corrected on .

    The bug is in Microsoft's C++ implementation code and it's gated by _HAS_ITERATOR_DEBUGGING so if disabling that is an option consider adding "_HAS_ITERATOR_DEBUGGING=0" to your "Preprocessor Definitions".

    If you don't like the idea of disabling iterator checking you'll need to workaround by disabling _HAS_ITERATOR_DEBUGGING so your code will look something like:

    struct Foo {
        int a;
        char b;
    };
    
    int main() {
        vector<Foo> test;
    
        for(int i = 0; i < 5; ++i) {
            Foo foo = { i + 1, 'a' + i };
    
            test.push_back(foo);
        }
    
    #if _HAS_ITERATOR_DEBUGGING
        for(vector<Foo>::const_iterator it = test.begin(); it != test.end(); ++it) {
            if(it->a > 2) {
                cout << it->b << endl;
                break;
            }
        }
    #else
        struct comp : public binary_function<const double, const Foo&, bool> {
            bool operator () (const double lhs, const Foo& rhs) { return lhs < rhs.a; }
        };
    
        cout << upper_bound(test.begin(), test.end(), 2, comp())->b << endl;
    #endif
    }
    

    A couple notes here:

    1. Note that I'm using a #if which means the if-block will only execute if _HAS_ITERATOR_DEBUGGING is defined and is non-0. At design time Visual Studio 2008 seems to always think that it is undefined
    2. My code defines comp inline if your particular situation requires comp to by used in multiple places 1st consider wrapping this entire else-block in a function to limit the number of #defines in your code, obviously the applicability of this comment will be limited if you're using comp in multiple standard algorithms