2
votes

I have the following code that cannot be compiled:

#include <iostream>
#include <set>
#include <functional>
#include <cstring>

using namespace std;

struct StringCompareNoRegister: public binary_function<string, string, bool> {
  bool operator()(string const& lhs, string const& rhs) const {
    return (_stricmp(lhs.c_str(), rhs.c_str()) < 0);
  }
};

int wmain() {
  set<string, StringCompareNoRegister> s;
  s.insert("hello");
  s.insert("STL");
  s.insert("Hello");
  wcout << s.find("Hello")->c_str() << endl;
  wcout << find(s.begin(), s.end(), "Hello")->c_str() << endl;

  return 0;
}

MVCPP v.11 CTP compiler yelling on the last line where std::find is used:

Error 1 error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const std::basic_string<_Elem,_Traits,_Alloc>' (or there is no acceptable conversion) c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility 3171

Why I cannot compile this code? What have I done wrong?

UPDATE: Full compiler output

1>------ Build started: Project: Test01, Configuration: Debug Win32 ------ 1> main.cpp 1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(3171): error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const std::basic_string<_Elem,_Traits,_Alloc>' (or there is no acceptable conversion) 1> with 1> [ 1> _Elem=char, 1> _Traits=std::char_traits, 1>
_Alloc=std::allocator 1> ] 1> could be 'built-in C++ operator==(const char [6], const char [6])' 1>
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(488): or 'bool std::operator ==(const std::_Exception_ptr &,const std::_Exception_ptr &)' 1>
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(493): or 'bool std::operator ==(std::_Null_type,const std::_Exception_ptr &)' 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(499): or 'bool std::operator ==(const std::_Exception_ptr &,std::_Null_type)' 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\system_error(419): or
'bool std::operator ==(const std::error_code &,const std::error_condition &)' 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\system_error(427): or 'bool std::operator ==(const std::error_condition &,const std::error_code &)' 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\tuple(537): or 'bool std::operator ==(const std::tuple<> &,const std::tuple<> &)' 1> while trying to match the argument list '(const std::basic_string<_Elem,_Traits,_Alloc>, const char [6])' 1>
with 1> [ 1> _Elem=char, 1>
_Traits=std::char_traits, 1> _Alloc=std::allocator 1> ] 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(3204) : see reference to function template instantiation '_InIt std::_Find,const char[6]>(_InIt,_InIt,_Ty (&))' being compiled 1> with 1>
[ 1>
_InIt=std::_Tree_unchecked_const_iterator,std::allocator>>>>, 1>
_Mytree=std::_Tree_val,std::allocator>>>, 1> _Ty=const char [6] 1> ] 1>
d:\docs\programming\test01\test01\main.cpp(39) : see reference to function template instantiation '_InIt std::find,const char[6]>(_InIt,_InIt,_Ty (&))' being compiled 1> with 1>
[ 1>
_InIt=std::_Tree_const_iterator,std::allocator>>>>, 1>
_Mytree=std::_Tree_val,std::allocator>>>, 1> _Ty=const char [6] 1> ] ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

3
Strange. After adding appropriate headers, etc., this works for me with GCC.Kaz Dragon
It seems that something wrong with MVCPP11 STL realization (or compiler)...nickolay
Please post the full code. Is string really std::string?Sebastian Mach
Couple of things to try: explicitly convert "Hello" to a std::string in the std::find call. Pass your functor to the std::find call. As it stands currently, your functor will not be used in that call, it'll use operator==. Also, could you post the entire build output (there's some additional diagnostics that appear to be missing).Nathan Ernst
@NathanErnst explicit conversion didn't help. std::find always use operator==. The build output added to the original post.nickolay

3 Answers

3
votes

Ops. The precise answer is that I've forgotten to add <string> header to includes. String header contains external (non-member) std::string comparison functions like operator==, operator<, etc.

Thank you very much for your answers.

2
votes

std::find does not use custom comparators in the same way. You need to overload the == operator.

The behavior is expected something like the below. Check cplusplus.com for the reference.

template<class InputIterator, class T>
  InputIterator find ( InputIterator first, InputIterator last, const T& value )
  {
    for ( ;first!=last; first++) if ( *first==value ) break;
    return first;
  }

So you would expect something like this if you were using a custom type.

struct Foo {
    Foo(const std::string &s_) : s(s_) {}
    std::string s;
    // used by std::set<Foo, Foo::Less>::find
    struct Less {
        bool operator()(const Foo &lhs, const Foo &rhs) const {
            return lhs.s.compare(rhs.s) < 0;
        }
    };
};

// used by std::find
bool operator==(const Foo &lhs, const Foo &rhs) {
    return lhs.s.compare(rhs.s) == 0;
}

int main(int argc, char ** argv) {
    std::set<Foo, Foo::Less> foos;
    foos.insert(Foo("hello"));
    foos.insert(Foo("STL"));
    foos.insert(Foo("Hello"));

    std::cout << foos.find(Foo("Hello"))->s.c_str() << std::endl;
    std::cout << find(foos.begin(), foos.end(), Foo("Hello"))->s << std::endl;
    return 0;
}   

Linux just found the operator for std::string, so I couldn't test your specific behavior. You may need to add some includes.

#include <algorithm>
#include <string>

Otherwise, defining your own is pretty painless.

bool operator==(const std::string &lhs, const std::string &rhs) {
    return lhs.compare(rhs) == 0;
}
0
votes

Hmm, try changing your functor args to bool operator()(const string & lhs, const string & rhs). See if that helps.