C++: Inserting pairs of class objects into a map - c++

I am trying to insert into a map that contains a class name_t object as the key and a class scores_t object as the value. The name_t object should be a string, while the scores_t object is a vector of ints. I am getting errors when trying to do:
map.insert(std::pair<string, vector<int> >(n.get(), s.get()));
The program code is:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <map>
#include <functional>
#include <algorithm>
#include <numeric>
#include <iomanip>
using namespace std;
class name_t{
public:
void print_name(int);
bool operator<(const name_t &rhs) const;
void set(string first, string last);
string get() const { return name; }
//Add get/set functions for firstname and lastname
private:
string name;
string firstname;
string lastname;
};
void name_t::print_name(int n){
cout << left << setw(21) << setfill('.') << name << " ";
}
bool name_t::operator<(const name_t &rhs) const{
if(get()!=rhs.get()) return get() < rhs.get();
return false;
}
void name_t::set(string first, string last){
firstname = first;
lastname = last;
name = lastname + ", " + firstname;
}
class scores_t{
public:
void push_back(int);
void compute_stats();
void print_scores();
vector<int> get(){ return scores; }
//Add accessor functions for min, max, avg, n80
private:
vector<int> scores;
int min;
int max;
int avg, n80;
};
void scores_t::push_back(int num){
scores.push_back(num);
}
void scores_t::compute_stats(){
vector<int>::iterator it;
it = min_element(scores.begin(), scores.end());
min = *it;
it = max_element(scores.begin(), scores.end());
max = *it;
int init = 0;
avg = accumulate(scores.begin(), scores.end(), init)/scores.size();
n80 = count_if(scores.begin(), scores.end(), bind2nd(greater<int>(),80));
}
void scores_t::print_scores(){
cout << min << " " << max << " " << avg << " " << n80;
scores.clear();
}
int main(int argc, char* argv[]){
name_t n;
scores_t s;
ifstream fin;
string first, last;
int num, size, bsize=0;
string text;
map<name_t, scores_t> map;
fin.open(argv[1]);
while(getline(fin, text)){
stringstream ss(text);
while(ss >> first >> last){
n.set(first, last);
size = first.size() + last.size();
if(size > bsize){
bsize = size;
}
n.print_name(bsize);
while(ss >> num){
cout << num << " ";
s.push_back(num);
}
cout << ": ";
s.compute_stats();
map.insert(std::pair<string, vector<int> >(n.get(), s.get()));
s.print_scores();
}
cout << endl;
}
fin.close();
return 0;
}
I am getting these errors:
In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:64:0,
from /usr/include/c++/4.8.2/bits/char_traits.h:39,
from /usr/include/c++/4.8.2/ios:40,
from /usr/include/c++/4.8.2/ostream:38,
from /usr/include/c++/4.8.2/iostream:39,
from Labstats1.cpp:1:
/usr/include/c++/4.8.2/bits/stl_pair.h: In instantiation of ‘std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = std::basic_string<char>; _U2 = std::vector<int>; _T1 = const name_t; _T2 = scores_t]’:
Labstats1.cpp:106:64: required from here
/usr/include/c++/4.8.2/bits/stl_pair.h:119:39: error: no matching function for call to ‘name_t::name_t(const std::basic_string<char>&)’
: first(__p.first), second(__p.second) { }
^
/usr/include/c++/4.8.2/bits/stl_pair.h:119:39: note: candidates are:
Labstats1.cpp:13:7: note: name_t::name_t()
class name_t{
^
Labstats1.cpp:13:7: note: candidate expects 0 arguments, 1 provided
Labstats1.cpp:13:7: note: name_t::name_t(const name_t&)
Labstats1.cpp:13:7: note: no known conversion for argument 1 from ‘const std::basic_string<char>’ to ‘const name_t&’
In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:64:0,
from /usr/include/c++/4.8.2/bits/char_traits.h:39,
from /usr/include/c++/4.8.2/ios:40,
from /usr/include/c++/4.8.2/ostream:38,
from /usr/include/c++/4.8.2/iostream:39,
from Labstats1.cpp:1:
/usr/include/c++/4.8.2/bits/stl_pair.h:119:39: error: no matching function for call to ‘scores_t::scores_t(const std::vector<int>&)’
: first(__p.first), second(__p.second) { }
^
/usr/include/c++/4.8.2/bits/stl_pair.h:119:39: note: candidates are:
Labstats1.cpp:43:7: note: scores_t::scores_t()
class scores_t{
^
Labstats1.cpp:43:7: note: candidate expects 0 arguments, 1 provided
Labstats1.cpp:43:7: note: scores_t::scores_t(const scores_t&)
Labstats1.cpp:43:7: note: no known conversion for argument 1 from ‘const std::vector<int>’ to ‘const scores_t&’
I'm not too sure what these errors mean. Any help is appreciated. Thank you!

Your map data type is std::pair<name_t, scores_t>, but you are trying to insert a pair of a std::string and std::vector - since this is what your get() functions are returning.
To solve the immediate compilation error, just use correct data type in insertion.
However, there are other, more subtle issues with your code. For instance, your get() functions return members by value. This means, that a copy will be made every time the function is called - and it takes quite a bite of time to copy the vector or string. Instead, you should expose your members through a function returning const reference.
Also, it is a good practice for a wrapper class (your classes are essentially wrappers) to define constructor which would take an argument of the wrapped type. For instance, for your name_t you might want a constructor like following:
name_t::name_t(const std::string& name) : name(name) {}

Related

Passing istream and string as functions parameters

I have the following code. What I'm trying to do is implement a word count function similar to wc in unix. It takes a file as input and gives back the number of lines, words and characters in that file.
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::vector< std::string> split(std::istream& is, char delim){
std::vector<std::string> result;
std::string elem;
while(std::getline(is, elem, delim))
{
if(elem != "")
result.push_back(std::move(elem));
}
return result;
}
std::vector< std::string> split(const std::string& val, char delim){
std::stringstream is(val);
return split(is, delim);
}
struct WCResult {
std::string Name;
std::size_t LineCount;
std::size_t WordCount;
std::size_t ByteCount;
WCResult(const std::string& name = "", std::size_t lc = 0, std::size_t wc = 0, std::size_t bc = 0): Name(name), LineCount(lc), WordCount(wc), ByteCount(bc)
{}
void output(std::ostream& os)
{
os << this->LineCount << " " << this->WordCount << " " << this->ByteCount << " " << this->Name << std::endl;
}
};
WCResult getWordCount(const std::istream& is, const std::string& name){
std::stringstream is_str(is); //Error1: argument types are: (const std::istream)
std::vector<std::string> linecount = split(is_str, '\n');
std::vector<std::string> wordcount = split(is, ' '); //Error2: argument types are: const std::istream, char)
std::size_t bytecount = 0;
for(std::string str : wordcount){
bytecount += str.size();
}
return WCResult{name, linecount.size(), wordcount.size(), bytecount};
}
int main(int argc, char** argv){
std::vector<std::string> args(argv, argv + argc);
std::ifstream file(args[1]);
WCResult wc_result = getWordCount(file, args[1]);
wc_result.output(std::cout);
return 0;
}
I'm trying to pass my file either as a string or as an input stream. It does work for the function std::vector< std::string> split(const std::string& val, char delim).
Why am I getting the errors?
Error:
src/newwc.cpp:45:48: error: binding reference of type ‘std::istream&’ {aka ‘std::basic_istream<char>&’} to ‘const istream’ {aka ‘const std::basic_istream<char>’} discards qualifiers
45 | std::vector<std::string> wordcount = split(is, ' ');
| ^~
src/newwc.cpp:7:46: note: initializing argument 1 of ‘std::vector<std::__cxx11::basic_string<char> > split(std::istream&, char)’
7 | std::vector<std::string> split(std::istream& is, char delim)
This is the only error i get when i compile, but the I also get another error in the IDE, which seems not to get caught when compiling.

Using c++ std::copy on an array of structure

I want to use std::copy to copy an existing array of structures to new one. A regular option is fine with '''local_copy()'''. I want to know the procedure to use std::copy for such case described below -
I tried the code and get following error at compile time
#include <iostream>
class BigClass{
public:
struct Astruct{
double x[2], v[2];
int rank;
}one_struct;
};
void allocate(struct BigClass::Astruct& one_struct, int i)
{
one_struct.x[0] = 1.1;
one_struct.x[1] = 1.2;
one_struct.v[0] = 2.1;
one_struct.v[1] = 2.2;
one_struct.rank = i;
}
void local_copy(struct BigClass::Astruct& dest, struct BigClass::Astruct& source)
{
dest.x[0] = source.x[0];
dest.x[1] = source.x[1];
dest.v[0] = source.v[0];
dest.v[1] = source.v[1];
dest.rank = source.rank;
}
void print(struct BigClass::Astruct one_struct)
{
std::cout << one_struct.rank << " " << one_struct.x[0] << " " << one_struct.x[1] << " " << one_struct.v[0] << " " << one_struct.v[1] << "\n";
}
int main(int argc, char *argv[]) {
int size = 10;
struct BigClass::Astruct BCobj[size];
for(int i = 0; i < size; i++) allocate(BCobj[i], i);
for(int i = 0; i < size; i++) print(BCobj[i]);
struct BigClass::Astruct second_BCobj[size];
//for(int i = 0; i < size; i++) local_copy(second_BCobj[i], BCobj[i]); // this works
for(int i = 0; i < size; i++) std::copy(BCobj[i+1], BCobj[i], second_BCobj[i]); // not working
for(int i = 0; i < size; i++) print(BCobj[i]);
}
The compile time error is following -
/usr/include/c++/7/bits/stl_algobase.h:377:57: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_II>::value_type _ValueTypeI;
^~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:378:57: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
^~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:379:64: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_II>::iterator_category _Category;
^~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:383:9: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
const bool __simple = (__is_trivial(_ValueTypeI)
~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __is_pointer<_II>::__value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __is_pointer<_OI>::__value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:386:44: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<BigClass::Astruct>’
return std::__copy_move<_IsMove, __simple,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_Category>::__copy_m(__first, __last, __result);
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
Some examples for vectors and int datatypes are available. Could anyone elaborate the appropriate sequence for std::copy for this kind of code structure?
Thanks.
std::copy is used instead of for loop, not with one.
std::copy(BCobj, BCobj + size, second_BCobj);
is essentially the same as
for(int i = 0; i < size; ++i) {
second_BCobj[i] = BCobj[i];
}
Also, don't forget to #include <algorithm> for std::copy
Explanation of arguments for std::copy:
std::copy takes as arguments 2 arguments of type matching InputIterator requirements and single argument of type OutputIteretor. Fortunately, pointers match these requirements, so we can use them directly. And because array name is interpreted as a pointer to its first element, we can pass it directly as argument to std::sort
Better version as suggested by Chef Gladiator:
std::copy(std::begin(BCobj), std::end(BCobj), std::begin(second_BCobj))
Welcome to Stack Overflow. You have presented your full code. Please next time also describe the development environment you are building in. Even better, try to present operating system agnostic and compiler agnostic, standard C++ code.
This is C++ forum, so we like to use standard C++ here. Your code is rewritten bellow using std::array. That makes it simple. Please study and enjoy the standard C++.
#include <array>
#include <iostream>
#include <algorithm>
namespace stack_overflow {
using namespace std;
struct BigClass final {
struct Astruct final {
double x[2], v[2];
int rank;
}one_struct;
friend ostream& operator << (ostream& os, Astruct const & one_struct)
{
return os << one_struct.rank << " " << one_struct.x[0] << " "
<< one_struct.x[1] << " " << one_struct.v[0] << " "
<< one_struct.v[1] ;
}
};
constexpr int size = 10;
using bcobj_arr = std::array<BigClass::Astruct, size>;
void populate( bcobj_arr& bcobjects_)
{
int j{ 0 };
for (auto& one_struct : bcobjects_) {
one_struct.x[0] = 1.1;
one_struct.x[1] = 1.2;
one_struct.v[0] = 2.1;
one_struct.v[1] = 2.2;
one_struct.rank = j++;
}
}
void print(const char prompt[BUFSIZ], bcobj_arr const & bcobjects_ )
{
cout << "\n\n" << prompt << "\n\n" ;
for (auto& one_struct : bcobjects_) {
cout << one_struct << "\n";
}
}
bool test (int argc, const char* argv[])
{
bcobj_arr BCobj;
populate(BCobj);
print("BCobj", BCobj);
// std::array instances can be copied
bcobj_arr second_BCobj = BCobj ;
print("second_BCobj", second_BCobj);
return true;
}
}
int main(const int argc, const char * argv[])
{
stack_overflow::test(argc, argv);
return 42;
}
Code is not commented at all. I assume you have a lot of questions, please do ask, in the comments bellow. I will try and answer them all by pointing you to the relevant documentation on-line.

std::for_each no known conversion for argument 1 from 'std::pair<const point, int>' to 'std::pair<point, int>&'

I cannot understand, as the both cases look so similar, in first for_each i cannot get reference to pair, and in second I get the reference to pair with no fuss. Could anybody please explain it to me?
#include <unordered_map>
#include <cstring>
#include <algorithm>
#include <iostream>
struct table_info_t {
char name[32] = {0};
int posx;
int posy;
table_info_t(const char *name, int posx, int posy) : posx(posx), posy(posy) {
strncpy(this->name, name, 31);
}
};
struct point {
int posx;
int posy;
point(int posx, int posy) : posx(posx), posy(posy) { }
};
size_t hashstruct(const char* hptr, size_t size) {
size_t h = 31;
for (size_t i = 0; i < size; i++) {
h = (h + *hptr) * 31;
hptr++;
}
return h;
}
#define MAP_OPERATORS(typ)\
namespace std {\
\
template<>\
struct hash<typ> {\
std::size_t operator()(const typ &k) const { return hashstruct((const char*)&k, sizeof(typ)); }\
};\
\
bool operator==(const typ& one, const typ& other) { return memcmp(&one, &other, sizeof(typ)) == 0; }\
};
MAP_OPERATORS(point); //hash structure and operator==
MAP_OPERATORS(table_info_t); //hash structure and operator==
int main(int argc, char** argv) {
std::unordered_map<point, int> sp;
sp[point(3, 4)] = 7;
std::for_each(sp.begin(), sp.end(),
[](std::pair<point, int> pair) {
std::cout << pair.first.posx << "+" <<pair.first.posy << "=" << pair.second << "\n";
});
std::unordered_map<table_info_t, const char *> m;
m[table_info_t("make my day", 3, 14)] = "make my day 3,14";
std::for_each(m.begin(), m.end(),
[](std::pair<const table_info_t, const char * >& pair)
{
std::cout << pair.first.name << pair.first.posx << pair.first.posy << " " << pair.second << "\n";
}
);
return 0;
}
Both structures do not differ so much, but when compiling this, I get this error:
In file included from .../4.8.2/include/c++/4.8.2/algorithm:62:0,
from .../src/main/c/hashtable.cpp:10:
.../4.8.2/include/c++/4.8.2/bits/stl_algo.h: In instantiation of '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = std::__detail::_Node_iterator<std::pair<const point, int>, false, true>; _Funct = main(int, char**)::__lambda0]':
.../src/main/c/hashtable.cpp:45:24: required from here
.../4.8.2/include/c++/4.8.2/bits/stl_algo.h:4417:14: error: no match for call to '(main(int, char**)::__lambda0) (std::pair<const point, int>&)'
__f(*__first);
^
.../src/main/c/hashtable.cpp:43:24: note: candidates are:
[](std::pair<point, int> &pair) {
^
In file included from .../4.8.2/include/c++/4.8.2/algorithm:62:0,
from .../src/main/c/hashtable.cpp:10:
.../4.8.2/include/c++/4.8.2/bits/stl_algo.h:4417:14: note: void (*)(std::pair<point, int>&) <conversion>
__f(*__first);
^
.../4.8.2/include/c++/4.8.2/bits/stl_algo.h:4417:14: note: candidate expects 2 arguments, 2 provided
.../src/main/c/hashtable.cpp:43:53: note: main(int, char**)::__lambda0
[](std::pair<point, int> &pair) {
^
.../src/main/c/hashtable.cpp:43:53: note: no known conversion for argument 1 from 'std::pair<const point, int>' to 'std::pair<point, int>&'
and I need to remove the reference. However reference to pair<const table_info_t, const char * > is perfectly fine for the compiler in second for_each.
When you iterate over std::unordered_map<Key, Value>,
you iterate on std::pair<const KEY, VALUE>
In the second case, you take std::pair<const KEY, VALUE>& so it is fine.
You might even add const as you don't change the pair: const std::pair<const KEY, VALUE>&.
In the first case, you use another type std::pair<KEY, VALUE>&.
std::pair<KEY, VALUE> can be constructed from std::pair<const KEY, VALUE>. However, a temporary can not be bound to non-const lvalue-reference. So using std::pair<KEY, VALUE>& is invalid. Using std::pair<KEY, VALUE> is valid but does extra copies. See unexpected copies with foreach over a map for details.
If you have access to C++14, you may simplify it using a generic lambda:
[](const auto& p) {
std::cout << p.first.posx << "+" << p.first.posy << "=" << p.second << "\n";
});
In addition std::for_each can also be replaced by a range-based for loop (even in C++11):
for(const auto& p : sp) {
std::cout << p.first.posx << "+" << p.first.posy << "=" << p.second << "\n";
};

std::sort error using custom classes

I have looked through stackoverflow and added an overload operator to hopefully make it work with sort. Though I still get an explosion of an error saying something is wrong with sort.
Code:
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <algorithm>
class Student
{
private:
std::string name_;
int number_;
std::vector<int> grades_;
const int num_courses_;
static std::string gen_name() {
return std::to_string(rand());
}
static int gen_number() {
return rand() % (201600000 - 201100000 + 1) + 201100000;
}
static int gen_grade() {
return rand() % (100 - 70 + 1) + 70;
}
double compute_average() {
int marks = 0;
int count = 0;
for (std::vector<int>::iterator i = grades_.begin(); i != grades_.end(); i++, count++){
marks += *i;
}
return static_cast<double>(marks) / count;
}
public:
Student() : name_(gen_name()), number_(gen_number()), num_courses_(5)
{
for (int i = 0; i < num_courses_; ++i) {
grades_.push_back(gen_grade());
}
}
double getAvg() {
return compute_average();
}
friend std::ostream& operator<<(std::ostream& os, Student& s) {
os << "Name = " << s.name_ << "\tNumber = " << s.number_ << "\tAvg = " << s.compute_average();
return os;
}
std::string getName() {
return name_;
}
void print_grades(std::ostream& os) const
{
for (int i = 0; i < num_courses_; ++i) {
os << grades_[i] << ", ";
}
}
bool operator < (const Student& str) const
{
return (name_ < str.name_);
}
};
int main(int argc, char ** argv) {
srand(time(NULL));
if (argc == 2){
int numbOfStudents = atoi(argv[1]);
std::vector<Student> studentVec;
for (int i = 0; i < numbOfStudents; i++){
studentVec.push_back(Student());
}
std::sort(studentVec.begin(), studentVec.end());
for (std::vector<Student>::iterator xi = studentVec.begin(); xi != studentVec.end(); xi++) {
std::cout << *xi << std::endl;
}
}
else{
std::cout << "Usage: " << argv[0] << " {numb} " << std::endl;
}
return 0
}
The error comes when I run sort (I know it's sort since if I comment it out, it works properly). With the error code
In file included from /usr/include/c++/4.9/algorithm:62:0,
from main.cpp:5:
/usr/include/c++/4.9/bits/stl_algo.h: In instantiation of ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Compare = __gnu_cxx::__ops::_Iter_less_iter]’:
/usr/include/c++/4.9/bits/stl_algo.h:1884:70: required from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Compare = __gnu_cxx::__ops::_Iter_less_iter]’
/usr/include/c++/4.9/bits/stl_algo.h:1970:55: required from ‘void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Compare = __gnu_cxx::__ops::_Iter_less_iter]’
/usr/include/c++/4.9/bits/stl_algo.h:4685:72: required from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >]’
main.cpp:79:50: required from here
/usr/include/c++/4.9/bits/stl_algo.h:1851:17: error: use of deleted function ‘Student& Student::operator=(Student&&)’
*__first = _GLIBCXX_MOVE(__val);
I searched earlier which helped me get to the result of adding a '<' overload, though I still get an error. Can anyone help point out where the mistake is? Thank you. (I compile using g++ --std=c++11)
the member variable const int num_courses_; is const, which means it must be set in the initializer list of the constructor.
num_courses_ can't be set by the copy assignment operator Student& Student::operator=(Student&&), so it prevent the compiler from generating the copy assignment operator for that class. Since there's no copy assignment operator available, and the std::sort function needs it to work, the compilation fails and complains about the copy assignment operator not being available.
Simply remove the const and declare the variable as int num_courses_ and your code should work.

binding of reference to a value of type drops qualifiers

I have the following source from the Text Accelerated C++. When I attempt to compile the source file I get the following compilation error listed below. I'm a novice of the C++ language so your assistance would be appreciated.
#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
using namespace std;
struct Student_info {
string name;
double midterm, final;
vector<double> homework;
};
double median(vector<double>);
double grade(const Student_info&);
double grade(double, double, double);
double grade(double, double, const vector<double>&);
istream& read_hw(istream&, vector<double>&);
istream& read(istream&, Student_info&);
bool compare(const Student_info&, Student_info&);
int main() {
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
while(read(cin, record)) {
maxlen = max(maxlen, record.name.size());
students.push_back(record);
}
sort(students.begin(), students.end(), compare);
for(vector<Student_info>::size_type i = 0;
i != students.size(); ++i) {
cout << students[i].name << string(maxlen + 1 - students[i].name.size(), ' ');
try {
double final_grade = grade(students[i]);
streamsize prec = cout.precision();
cout << setprecision(3) << final_grade
<< setprecision(prec);
} catch(domain_error& e) {
cout << e.what();
}
cout << endl;
}
return 0;
}
double median(vector<double> vec) {
typedef vector<double>::size_type vec_sz;
vec_sz size = vec.size();
if(size == 0)
throw domain_error("median of an empty vector");
sort(vec.begin(), vec.end());
vec_sz mid = size/2;
return size%2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid];
}
double grade(const Student_info& s) {
return grade(s.midterm, s.final, s.homework);
}
double grade(double midterm, double final, double homework) {
return 0.2*midterm + 0.4*final + 0.4*homework;
}
double grade(double midterm, double final, const vector<double>& hw) {
if(hw.size() == 0)
throw domain_error("student has done no homework");
return grade(midterm, final, median(hw));
}
istream& read_hw(istream& in, vector<double>& hw) {
if(in) {
hw.clear();
double x;
while(in >> x)
hw.push_back(x);
in.clear();
}
return in;
}
istream& read(istream& is, Student_info& s) {
is >> s.name >> s.midterm >> s.final;
read_hw(is, s.homework);
return is;
}
bool compare(const Student_info& x, const Student_info& y) {
return x.name < y.name;
}
binding of reference to type 'Student_info' to a value of type 'const Student_info' drops qualifiers compute_grades_rev-b
line 125, external location: /usr/include/c++/4.2.1/bits/stl_algo.h C/C++ Problem
Here is the code from stl_algo.h:
template<typename _Tp, typename _Compare>
inline const _Tp&
__median(const _Tp& __a, const _Tp& __b, const _Tp& __c, _Compare __comp)
{
// concept requirements
__glibcxx_function_requires(_BinaryFunctionConcept<_Compare,bool,_Tp,_Tp>)
if (__comp(__a, __b))
if (__comp(__b, __c))
return __b;
else if (__comp(__a, __c))
return __c;
else
return __a;
else if (__comp(__a, __c))
return __a;
else if (__comp(__b, __c))
return __c;
else
return __b;
}
I change the declaration of the compare function from:
bool compare(const Student_info&, Student_info&);
bool compare(const Student_info, Student_info);
Now it compiles.
The error is indicating that you cannot bind a non-const reference to a const-object, as that would drop (discard in other compiler's errors), disregard or ignore the const qualifier.
What it tries to indicate is that if the operation was allowed you would be able to modify the object through the reference ignoring the fact that the object itself is const, breaking const-correctness.
In your particular code, the function __median in the library takes __a, __b, and __c by const reference and tries to call the __comp function, which in your program (first declaration) takes the second argument by non-const reference. To be able to call __comp(__a,__b) (or any other call to __comp in that function) it would have to bind an object accessible only through a const& to the second argument that takes a non-const reference. This is most probably a typo, since you define compare below with both arguments being const references.
Change the declaration of compare before main to:
bool compare(const Student_info&, const Student_info&);
// ^^^^^
the error: binding reference of type ‘((type))&’ to ‘const ((type))’ discards qualifiers can also originate from a const member function of a class, like void MyClass::myFunc() const {}
#include <iostream>
// comment next line to make code work
#define BROKEN
class C2 {
public:
void f(int &i);
};
void C2::f(int &i) { i++; }
class C1 {
public:
C1();
int i;
C2 c2; C2* pc2;
void f_nonconst();
void f_const() const;
};
C1::C1() { c2 = C2(); pc2 = &c2; }
void C1::f_nonconst() {
pc2->f(i);
// no error
}
#ifdef BROKEN
void C1::f_const() const {
pc2->f(i);
// error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
}
#endif
#define print_i() { std::cout << "i = " << pc1->i << std::endl; }
int main() {
C1 c1 = C1();
C1* pc1 = &c1;
print_i(); pc1->f_nonconst();
#ifdef BROKEN
print_i(); pc1->f_const();
#endif
print_i();
}
related to Meaning of 'const' last in a function declaration of a class?