how to std::sort with a custom comp belonging to a class ?

Here is what I would like to do (I simplified it) and which fails to compile :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <algorithm>

class Toto {
public:
	int mSize;
	int mpV[5];
	Toto() {mSize = 5; mpV[0] = 50;  mpV[1] = 10; mpV[2] = 40; mpV[3] = 30; mpV[4] = 20;}
	bool is_higher(int a1, int a2) {return (a1 > a2);}
	void my_sort() {sort(mpV, mpV + mSize, is_higher);} // #include <algorithm>
};

int main(int argc, const char *argv[]) {
	switch (atoi(argv[1])) {
		case 21 : {
			Toto t;
			t.my_sort();
			cout << "t = "; for (int i = 0; i < t.mSize; i++) cout << t.mpV[i] << " "; cout << endl;
		}
	}

	return 0;
}


With Toto::is_higher in the argument of sort, it changes nothing :

void my_sort() {sort(mpV, mpV + mSize, Toto::is_higher);} // #include

Here are the compiler outputs (first lines) :
make all 
Building file: ../src/test.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/alain/Documents/Poker/WorkSpace/MyUtils" -Ipthread -I/usr/include/tbb -O3 -Wall -c -fmessage-length=0 -std=c++0x -std=gnu++0x -MMD -MP -MF"src/test.d" -MT"src/test.d" -o"src/test.o" "../src/test.cpp"
../src/test.cpp: In member function 'void Toto::my_sort()':
../src/test.cpp:45:50: erreur: argument of type 'bool (Toto::)(int, int)' does not match 'bool (Toto::*)(int, int)'
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/algorithm:63:0,
                 from ../src/test.cpp:16:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h: In function 'void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int*, _Compare = bool (Toto::*)(int, int)]':
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h:2192:4:   instantiated from 'void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = int*, _Compare = bool (Toto::*)(int, int)]'
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h:5252:4:   instantiated from 'void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = int*, _Compare = bool (Toto::*)(int, int)]'


The point looks to be : "argument of type 'bool (Toto::)(int, int)' does not match 'bool (Toto::*)(int, int)'". But I don't figure out what to do with that.

If I put is_higher outside of the class, it works :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <algorithm>

bool is_higher(int a1, int a2) {return (a1 > a2);}

class Toto {
public:
	int mSize;
	int mpV[5];
	Toto() {mSize = 5; mpV[0] = 50;  mpV[1] = 10; mpV[2] = 40; mpV[3] = 30; mpV[4] = 20;}
	void my_sort() {sort(mpV, mpV + mSize, is_higher);} // #include <algorithm>
};

int main(int argc, const char *argv[]) {
	switch (atoi(argv[1])) {
		case 21 : {
			Toto t;
			t.my_sort();
			cout << "t = "; for (int i = 0; i < t.mSize; i++) cout << t.mpV[i] << " "; cout << endl;
		}
	}

	return 0;
}


But I do need to have it in the class in the real case. How can I do it please ?
Make it a static member function.
Thanks kbw. But then I cannot use non static members - and I need to. Another idea please ?

Let's replace the is_higher function declaration by :

static bool is_higher(int a1, int a2) {if (mSize == 5) return (a1 > a2); else return (false);}

make all 
Building file: ../src/test.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/alain/Documents/Poker/WorkSpace/MyUtils" -Ipthread -I/usr/include/tbb -O3 -Wall -c -fmessage-length=0 -std=c++0x -std=gnu++0x -MMD -MP -MF"src/test.d" -MT"src/test.d" -o"src/test.o" "../src/test.cpp"
../src/test.cpp: In static member function 'static bool Toto::is_higher(int, int)':
../src/test.cpp:42:6: erreur: invalid use of member 'Toto::mSize' in static member function
../src/test.cpp:47:45: erreur: à partir de cette localisation
../src/test.cpp:47:95: attention : contrôle a atteint la fin non void de la fonction
make: *** [src/test.o] Erreur 1

Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
struct Toto
{
    // ... 

    bool is_higher(int a1, int a2) const { return a1 > a2) ; }
    

    void my_sort1() // C++11: use a lambda // 1
    {
        sort( mpV, mpV + mSize,
              [this]( int a, int b ) { return this->is_higher(a,b) ; } ) ;
    }


    void my_sort2() // C++11: use std::bind in <functional> // 2
    {
        using namespace std::placeholders ;
        sort( mpV, mpV + mSize, std::bind( &Toto::is_higher, this, _1, _2 ) ) ;
    }

    
    void my_sort3() // C++98 : use boost::bind in <boost/bind.hpp> // 3
    { sort( mpV, mpV + mSize, boost::bind( &Toto::is_higher, this, _1, _2 ) ) ; }
    
    
    void my_sort4() ; // C++98 : use a helper  // 4
};

struct helper
{
    explicit helper( const Toto& t ) : tt(t) {}
    bool operator() ( int a, int b ) const { return tt.is_higher(a,b) ; }
    const Toto& tt ;
};

void Toto::my_sort4() { sort( mpV, mpV + mSize, helper(*this) ) ; }

Use a function object. (non member)

e.g.
1
2
3
4
5
struct greaterThan{
  bool operator() (int i,int j) { return (i>j);}
}

void Toto::my_sort() {sort(mpV, mpV + mSize, greaterThan);}
Last edited on
Use a function object. (non member)
1
2
3
4
5
struct greaterThan{
  bool operator() (int i,int j) { return (i>j);}
};

void Toto::my_sort() {sort(mpV, mpV + mSize, greaterThan);}


This particular function object won't do at all: 'But then I cannot use non static members - and I need to'

Tip: A function object should ideally be immutable / idempotent_wrt_copy, which implies that the overloaded function-call operator should have a const qualifier.
Last edited on
closed account (zwA4jE8b)
OP, for some reason gcc will not let you (at least it will not let me) declare a class variable in a switch/case. For trial purposes, declare your class elsewhere, or if you can a pointer to your class, then in the switch/case you can allocate it with new.
Thanks a lot JLBorges. I like very much your my_sort3() solution with std::bind. It is the most readable for me and make sense. All of that is new for me : bind, lambda functions, explicit.

Thanks CreativeMFS. It is actually good to know. I usually don't do that. This code is only a breadboard. But I did not know and looks like a bug. Isn't it ?
> for some reason gcc will not let you (at least it will not let me) declare a class variable in a switch/case.

It will, if the definition is within a local scope that does not span case labels. Or if there are no more case labels to follow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Toto { public: Toto() {} ~Toto() {} } ;

int main( int argc, char* argv[] )
{
    switch( argc )
    {
        case 0 :
        {
            Toto x ; // this is fine, x is destroyed at end of scope
        }

        case 1 :
            //Toto y ; //  *** error *** this is not - a case label crosses the path
                     // between the construction and the destruction of y

        case 2 :
            Toto z ; // this too is fine; there are no case labels to follow
    }
}

Strange, I had an error at compilation with using namespace std::placeholders; :

'placeholders' is not a namespace-name


..... in my real project but not in my breadboard. So I checked for the #include directives that are more numerous in my breadboard and I could solve it by adding :

#include <thread>

Then I checked the declarations of <thread> :

1
2
3
4
5
6
7
8
9
10
#ifndef _GLIBCXX_THREAD
#define _GLIBCXX_THREAD 1

#pragma GCC system_header

#ifndef __GXX_EXPERIMENTAL_CXX0X__
# include <bits/c++0x_warning.h>
#else

#endif // _GLIBCXX_THREAD 


The fun is that if I replace #include <thread> with that, adding a #endif that is missing, I am back to 'placeholders' is not a namespace-name

If you have an explanation.....
Get rid of the #include <thread> - you don't need it.

And add #include <functional> - you do need it for std::bind() and std::placeholders
Thanks.
Topic archived. No new replies allowed.