1

So I was trying to add to a class a function that compares two std::string's disregarding case from here: Case insensitive standard string comparison in C++.

#include <iostream>
#include <string>
using namespace std;

class foo {
    public:
        bool icompare_pred(char a, char b) {
             return std::tolower(a) == std::tolower(b);
        }
        bool icompare( string a,  string  b){
            return  equal( a.begin(),  a.end(),  b.begin(),  icompare_pred);
        }
};  

int main() {

}

The code doesn't compile, even more: it sends me into the depths of STL with an error

[Error] must use '.*' or '->*' to call pointer-to-member function in '__binary_pred (...)', e.g. '(... ->* __binary_pred) (...)'

in this part

stl_algobase.h
 template<typename _IIter1, typename _IIter2, typename _BinaryPredicate>
inline bool
equal(_IIter1 __first1, _IIter1 __last1,
  _IIter2 __first2, _BinaryPredicate __binary_pred)
{
  // concept requirements
  __glibcxx_function_requires(_InputIteratorConcept<_IIter1>)
  __glibcxx_function_requires(_InputIteratorConcept<_IIter2>)
  __glibcxx_requires_valid_range(__first1, __last1);

  for (; __first1 != __last1; ++__first1, ++__first2)
if (!bool(__binary_pred(*__first1, *__first2)))
  return false;
  return true;
}

Well, what do I do? How do I fix this error?

Community
  • 1
  • 1
RICHnsk
  • 13
  • 3
  • Make sure to include all the required headers. You're missing `algorithm`, and possibly others. – juanchopanza Apr 24 '16 at 17:16
  • This is the basic fact that a member function cannot be used through the same kind of function pointer as a non-member function. (It has its own, but they're distinct and not implicitly convertible, for obvious reasons.) – underscore_d Apr 24 '16 at 17:19

4 Answers4

2

You should use static function as predicate:

static bool icompare_pred(char a, char b) {
^^^^^^

or you can use lambda:

bool icompare( string a,  string  b){
     return  equal( a.begin(),  a.end(),  b.begin(),  
                      [](char a, char b){return std::tolower(a) == std::tolower(b);});
 }
marcinj
  • 48,511
  • 9
  • 79
  • 100
2

Make icompare_pred() a static function of foo

    static bool icompare_pred(char a, char b) {
 // ^^^^^^
         return std::tolower(a) == std::tolower(b);
    }

or move the function out of the class foo as free function.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
1

You would need your comparator to be static

static bool icompare_pred(char a, char b) {
    return std::tolower(a) == std::tolower(b);
}

Also since icompare isn't static, you'd have to call it from a foo instance, like so

int main()
{
    foo f;
    std::cout << f.icompare("TEST", "test");
}

Live demo, output

1
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
1

There are multiple errors in your code, some of which are apparently not caught by your compiler (due to its permissiveness?). For example, icompare_pred by itself is not a valid C++ expression. Non-static member function names by themselves do not form valid expressions in C++. You have to either call the function using () operator or form a pointer to it using & operator and a qualified name. What you are trying to do would be properly expressed as

bool icompare( string a,  string  b){
  return  equal( a.begin(),  a.end(),  b.begin(), &foo::icompare_pred);
}

Both the & operator and the foo:: prefix are mandatory.

And this is where we run into the second error. A two-parameter non-static member function actually has three parameters: the two that you declared explicitly and an implicit this parameter. So, in your code you are passing a three-parameter function where a two-parameter one is required. This is one way to "interpret" this error.

In order to make your member function usable as a predicate for std::equal you can "bind" the implicit this parameter - attach a specific fixed value to it - thus converting a three-parameter function into a two-parameter one. For example

bool icompare( string a,  string  b){
  return  equal( a.begin(),  a.end(),  b.begin(),  
    std::bind(&foo::icompare_pred, this, 
      std::placeholders::_1, std::placeholders::_2));
}

This should compile and work as intended.

However, since your comparison predicate does not really need or care about that implicit this parameter, a better approach would be to get rid of it entirely: just declare your comparator as static, as suggested in other answers. If you do that, the &foo::icompare_pred syntax will become unnecessary as well and you'll be able to just use icompare_pred in its place as in your original code.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765