binary '<': no operator found


when i run this code, i get this error:


Severity Code Description Project File Line Suppression State
Error C2678 binary '<': no operator found which takes a left-hand operand of type 'const studentinfo' (or there is no acceptable conversion) studentrecord c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.10.25017\include\xstddef 234



i am not sure why. i am not even using the "<" operator.



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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# include <iostream>
# include <algorithm>
# include <vector>
# include <list>
# include <string>
# include <set>


using namespace std;

struct studentinfo {
	string name;
	int grade;
};


class markinfo {

public:

	vector<studentinfo> pass;
	vector <studentinfo> fail;

};


markinfo passfail( const vector<studentinfo>  & s)
{
	markinfo m;

	for(auto x:s)

	if (x.grade >= 50)
	{
		m.pass.push_back(x); 
	}
	else
	{
		m.fail.push_back(x);
	}

	return m; 

}


ostream& operator <<(ostream& os, studentinfo & c)
{
	os << c.name << " " << c.grade ;
	return os;

}



//
//template<typename T>
//void print(T& c)
//{
//	cout << "\nHere is the List: \n";
//	for (auto& x : c)			//& pass by ref is required if process modifies the element
//		cout << x << "  ";
//	cout << "\n" << endl;
//}




bool name(const studentinfo & lhs, const studentinfo & rhs)
{
	return lhs.name < rhs.name; 
}


int main()
{

	vector <studentinfo> s;

	studentinfo sinfo;
	sinfo.name = "gg";
	sinfo.grade = 44;

	studentinfo sinfo2;
	sinfo2.name = "aa";
	sinfo2.grade = 77;

	s.push_back(sinfo);
	s.push_back(sinfo2);

	sort(s.begin(), s.end(), name); 

	markinfo m;

	m = passfail(s);
	cout << " test " << endl; 


	list <studentinfo> l;

	std::list<studentinfo> lst{ s.begin(), s.end() };

	set<studentinfo> ss(s.begin(), s.end()); 

	//print(lst); 

	//print(ss); 


	for (auto& x : s)			//& pass by ref is required if process modifies the element
		cout << x << endl;


	
	//l.insert((s.begin(), s.end()));


	//ist <studentinfo> ll = ;

	/*
	for (auto x : m.pass)
	{
		cout << x.name << x.grade << endl;
	}*/

	
	for (auto x : s)
	{
		cout << x.name << x.grade << endl;
	}
	
	system("pause");
	

}
 
I think
1
2
3
4
bool name(const studentinfo & lhs, const studentinfo & rhs)
{
	return lhs.name < rhs.name; 
}

might be your problem. You should have an overload less than operator.
Last edited on
how should i overload it ?
You are using std::sort() correctly, and even made a sort function (which you named 'name' ???).

The problem is that a std::set() wants to sort its elements, but has no idea how to sort studentinfos. This is where the < operator comes in: you want to provide a version that knows how to work on studentinfo arguments.

Your 'name' function is exactly that, just with the unfortunate name. Rewrite it thus:

1
2
3
4
bool operator < (const studentinfo & lhs, const studentinfo & rhs)
{
	return lhs.name < rhs.name;
}

You will also want to change the sorting in main():

 
sort(s.begin(), s.end());


You can also get rid of those live-for-too-long temporaries to build your list:

1
2
3
4
5
6
int main()
{
	s.emplace_back( studentinfo { "gg", 44 } );
	s.emplace_back( studentinfo { "aa", 77 } );

	sort(begin(s), end(s));

Hope this helps.
Other hints:
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# include <algorithm>
# include <iostream>
# include <string>
# include <vector>

struct studentinfo {
    std::string name;
    int grade;
    bool operator<(const studentinfo& other);
};

bool studentinfo::operator<(const studentinfo& other)
{ return name < other.name; }

class markinfo {
public:
    std::vector<studentinfo> pass;
    std::vector<studentinfo> fail;
};

markinfo passfail(const std::vector<studentinfo>& s)
{
    markinfo m;
    for(auto x : s) {
        if (x.grade >= 50) { m.pass.push_back(x); }
        else               { m.fail.push_back(x); }
    }
    return m;
}

std::ostream& operator <<(std::ostream& os, const studentinfo& c)
{ return os << c.name << ' ' << c.grade; }

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

int main()
{
    std::vector<studentinfo> sinfos { { "John Smith", 44 }, 
                                      { "Ann Allen", 77 } };

    std::sort(sinfos.begin(), sinfos.end());

    markinfo m = passfail(sinfos);
    std::cout << "Test:\n";
    for(const auto& x : m.pass) { std::cout << x << '\n'; }
    for(const auto& x : m.fail) { std::cout << x << '\n'; }
    waitForEnter();
    return 0;
}

i thought i could define a predicate function such as:

bool name(const studentinfo & lhs, const studentinfo & rhs)
{
return lhs.name < rhs.name;
}


and then just call it :


sort(s.begin(), s.end(), name);
i thought i could define a predicate function such as:
1
2
bool name(const studentinfo & lhs, const studentinfo & rhs)
{    return lhs.name < rhs.name;   }

and then just call it :
sort(s.begin(), s.end(), name);

Pretty near. You can’t use a ‘normal’ function, but a ‘function object’, i.e.: a ‘thing’ that behaves like a function:
http://en.cppreference.com/w/cpp/algorithm/sort
1
2
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

...
comp - comparison function object


A function object can be for example a functor (a class a member of which overloads operator() ), a lambda (which is converted into a functor by the compiler), all these strange ‘beasts’ here:
http://en.cppreference.com/w/cpp/utility/functional

So, following the examples provided by cppreference.com, you can:
1) wrap your ‘normal’ function into a function object by means of std::function:
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
37
# include <algorithm>
# include <functional>
# include <iostream>
# include <string>
# include <vector>

struct studentinfo {
    std::string name;
    int grade;
};

bool name(const studentinfo & lhs, const studentinfo & rhs);
void waitForEnter();

int main()
{
    std::vector<studentinfo> sinfos { { "John Smith", 44 }, 
                                      { "Ann Allen", 77 } };

    std::function<bool(const studentinfo&, const studentinfo&)> myname = name;
    std::sort(sinfos.begin(), sinfos.end(), myname);

    for(const auto& e : sinfos) { 
        std::cout << "Name: " << e.name << " --> " << e.grade << '\n';
    }
    waitForEnter();
    return 0;
}

bool name(const studentinfo & lhs, const studentinfo & rhs)
{ return lhs.name < rhs.name; }

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}


2) write your own functor:
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
37
38
39
# include <algorithm>
# include <iostream>
# include <string>
# include <vector>

struct studentinfo {
    std::string name;
    int grade;
};

struct {    // unnamed struct
    // Overloading operator() to build a functor
    bool operator()(const studentinfo& lhs, const studentinfo& rhs) const
    {
        return lhs.name < rhs.name; 
    }
} mycomp;   // beware: this is an instance of the unnamed struct

void waitForEnter();

int main()
{
    std::vector<studentinfo> sinfos { { "John Smith", 44 }, 
                                      { "Ann Allen", 77 } };

    std::sort(sinfos.begin(), sinfos.end(), mycomp);

    for(const auto& e : sinfos) { 
        std::cout << "Name: " << e.name << " --> " << e.grade << '\n';
    }
    waitForEnter();
    return 0;
}

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}


3) use a lambda:
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
# include <algorithm>
# include <iostream>
# include <string>
# include <vector>

struct studentinfo {
    std::string name;
    int grade;
};

void waitForEnter();

int main()
{
    std::vector<studentinfo> sinfos { { "John Smith", 44 }, 
                                      { "Ann Allen", 77 } };

    std::sort(sinfos.begin(), sinfos.end(), 
              [](const studentinfo& left, const studentinfo& right) {
                  return left.name < right.name;
              } );

    for(const auto& e : sinfos) { 
        std::cout << "Name: " << e.name << " --> " << e.grade << '\n';
    }
    waitForEnter();
    return 0;
}

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}


Errors and Omissions Excepted :-)

> i thought i could define a predicate function such as: ...

>> You can’t use a ‘normal’ function

We can use a 'normal' function, as long as it meets the requirements specified by the Compare concept
http://en.cppreference.com/w/cpp/concept/Compare

A pointer to the 'normal' function can also be used as the compare object for std::set.

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>

struct sinfo {

    std::string name;
    int grade;
};

bool cmp_names( const sinfo& lhs, const sinfo& rhs ) { return lhs.name < rhs.name ; }

int main()
{
    std::vector<sinfo> vec { { "gg", 44 }, { "aa", 77 }, { "dd", 52 }, { "cc", 02 } };

    std::sort( vec.begin(), vec.end(), cmp_names );

    for( const auto& si : vec )
        std::cout << "Name: " << si.name << "  grade: " << si.grade << '\n' ;

    std::cout << '\n' ;

    std::set< sinfo, decltype(&cmp_names) > set( vec.begin(), vec.end(), &cmp_names ) ;

    for( const auto& si : set )
        std::cout << "Name: " << si.name << "  grade: " << si.grade << '\n' ;
}

http://coliru.stacked-crooked.com/a/ee3cb0ce8585f710
JLBorges wrote:
We can use a 'normal' function, as long as it meets the requirements specified by the Compare concept

Definitely, JLBorges! Thanks a lot for your correction. I’ve been set on the wrong track by the error the OP reported (“Error C2678 binary '<': no operator found which takes a left-hand operand of type 'const studentinfo'”), which was likely due by the (wrong) sort() on std::set, not the one on std::vector, which was fine.
I gave a hasty answer: my bad.
what is the difference btw these 2:

bool cmp_names(const studentinfo & lhs, const studentinfo & rhs)
{
return lhs.name < rhs.name;
}

and:

bool cmp_names( const sinfo& lhs, const sinfo& rhs ) { return lhs.name < rhs.name ; }

i have changed my code , but i am still getting this error:


# include <iostream>
# include <algorithm>
# include <vector>
# include <list>
# include <string>
# include <set>


using namespace std;

struct studentinfo {
string name;
int grade;
};


class markinfo {

public:

vector<studentinfo> pass;
vector <studentinfo> fail;

};


markinfo passfail( const vector<studentinfo> & s)
{
markinfo m;

for(auto x:s)

if (x.grade >= 50)
{
m.pass.push_back(x);
}
else
{
m.fail.push_back(x);
}

return m;

}


ostream& operator <<(ostream& os, studentinfo & c)
{
os << c.name << " " << c.grade ;
return os;

}



//
//template<typename T>
//void print(T& c)
//{
// cout << "\nHere is the List: \n";
// for (auto& x : c) //& pass by ref is required if process modifies the element
// cout << x << " ";
// cout << "\n" << endl;
//}


//
//
//bool cmp_names(const studentinfo & lhs, const studentinfo & rhs)
//{
// return lhs.name < rhs.name;
//}


bool cmp_names(const studentinfo& lhs, const studentinfo& rhs) { return lhs.name < rhs.name; }



int main()
{

vector <studentinfo> s;

studentinfo sinfo;
sinfo.name = "gg";
sinfo.grade = 44;

studentinfo sinfo2;
sinfo2.name = "aa";
sinfo2.grade = 77;

s.push_back(sinfo);
s.push_back(sinfo2);

sort(s.begin(), s.end(), cmp_names);

markinfo m;

m = passfail(s);
cout << " test " << endl;


list <studentinfo> l;

std::list<studentinfo> lst{ s.begin(), s.end() };

set<studentinfo> ss(s.begin(), s.end());

//print(lst);

//print(ss);


for (auto& x : s) //& pass by ref is required if process modifies the element
cout << x << endl;



//l.insert((s.begin(), s.end()));


//ist <studentinfo> ll = ;

/*
for (auto x : m.pass)
{
cout << x.name << x.grade << endl;
}*/


for (auto x : s)
{
cout << x.name << x.grade << endl;
}

system("pause");


}
> i have changed my code , but i am still getting this error:

Repeat:
1
2
// set<studentinfo> ss(s.begin(), s.end()); 
std::set< studentinfo, decltype(&cmp_names) > ss( s.begin(), s.end(), &cmp_names );

This version compiles:
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# include <algorithm>
# include <iostream>
# include <limits>
# include <list>
# include <set>
# include <string>
# include <vector>

using namespace std;

struct studentinfo {
    string name;
    int grade;
    bool operator<(const studentinfo& other) const { return name < other.name; }
};


class markinfo {
public:
    vector<studentinfo> pass;
    vector <studentinfo> fail;
};


markinfo passfail( const vector<studentinfo> & s)
{
    markinfo m;

    for(auto x:s)
        if (x.grade >= 50)
        {
            m.pass.push_back(x);
        }
        else
        {
            m.fail.push_back(x);
        }
    return m;
}

ostream& operator <<(ostream& os, studentinfo & c)
{
    os << c.name << " " << c.grade ;
    return os;
}

bool cmp_names(const studentinfo& lhs, const studentinfo& rhs) { return lhs.name < rhs.name; }

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

int main()
{

    vector <studentinfo> s;

    studentinfo sinfo;
    sinfo.name = "gg";
    sinfo.grade = 44;

    studentinfo sinfo2;
    sinfo2.name = "aa";
    sinfo2.grade = 77;

    s.push_back(sinfo);
    s.push_back(sinfo2);

    sort(s.begin(), s.end(), cmp_names);

    markinfo m;

    m = passfail(s);
    cout << " test " << endl;

    list <studentinfo> l;
    std::list<studentinfo> lst{ s.begin(), s.end() };
    set<studentinfo> ss(s.begin(), s.end());

    for (auto& x : s)
    cout << x << endl;

    for (auto x : s)
    {
        cout << x.name << x.grade << endl;
    }
    waitForEnter();
}

Last edited on
how is it different from the one i have posted before ?
how is it different from the one i have posted before ?

My code mainly differ from yours in this line:
bool operator<(const studentinfo& other) const { return name < other.name; }

JLBorges offered you a different solution, which doesn’t involve any modification of your structs.
why is it necessary to have this line inside the struct:

bool operator<(const studentinfo& other) const { return name < other.name; }

i thought that the predicate function on line 47 takes care of everything:


bool cmp_names(const studentinfo& lhs, const studentinfo& rhs) { return lhs.name < rhs.name; }
why is it necessary to have this line inside the struct:
bool operator<(const studentinfo& other) const { return name < other.name; }
i thought that the predicate function on line 47 takes care of everything:
bool cmp_names(const studentinfo& lhs, const studentinfo& rhs) { return lhs.name < rhs.name; }

Your post would be so much easier to read if you had used the “code” tags...

cmp_names() can take care of everything if you pass it to the std::set constructor, as JLBorges showed you:
JLBorges wrote:
std::set< studentinfo, decltype(&cmp_names) > ss( s.begin(), s.end(), &cmp_names );

Topic archived. No new replies allowed.