Hi, do any of you know a way to refer to members of a struct abstractly?
For instance, with the given struct:
struct person {
int age;
string name;
int height;
}
I want to do something like
person jim;
cout << jim.1; //displays age
This is important to me because i have a program with an array of structs. I want to sort this array by any of the member criterias. I.e. with the sample struct given above, an array of people could be sorted by age, name, or height. I do NOT want to have to write multiple sort functions for each member. Is there any way to refer to these struct members abstractly?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
First... euck! I cant help thinking that whatever you are trying to do, this is a nasty way of doing it.
You don't need to write "multiple sort functions" in any case. Consider using the C library's qsort() function, then all you need is a compare function for each member (either way you need a different function for each member because they are different types!):
struct person
{
int age;
string name;
int height;
static int cmpAge( void a, void b)
{
return (person)b->age - (person)a->age
}
static int cmpName( void a, void b)
{
return (((person)a->name < (person)b->name) ? -1 : (((person)a->name > (person)b->name) ? 1 : 0)) ;
}
static int cmpHeight( void a, void b)
{
return (person)b->height - (person)a->height
}
}
This is actually quite a cumbersome method, a far better way would be to use an STL container class rather than an array. That would enable you to use the STL <algorithms> sort function. This still requires you to write comparison functions - there is no getting away from that - however the comparison functions are simpler, because they only return two states (true/false).
Clifford, Clifford seriously, i could kiss you. I never knew the STL had that sort functionality. You just single-handedly solved my problem and optimized my code immensely with the same solution.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Except i had a problem implementing it. In a test file, everything worked great. Now that i implement it into a function of a class, it gives me these errors:
97 C:\Documents and Settings\Aspire II\Desktop\structreadwrite.cpp no matching function for call to 'sort(gnu_cxx::normal_iterator<employee, std::vector<employee, std::allocator<employee> > >, gnu_cxx::normal_iterator<employee, std::vector<employee, std::allocator<employee> > >, <unknown type>)'
Found on another forum: You can't use sort with member functions. Period. There are more technical details to this, but they really don't matter. What's the point of an implementation like this that can't handle classes? The STL wasn't built in the 80s or anything. Oh well. Thanks anyway, Clifford.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
void special::dostuff() {
//Create a vector of structs and load it
vector<person> myvector;
person jim = {22,"jim",175};
person frank = {23,"frank",500};
person hank = {25,"hank",222};
myvector.push_back(jim);
myvector.push_back(frank);
myvector.push_back(hank);
//Call STL's sort THIS LINE CAUSES THE ERROR
sort (myvector.begin(), myvector.end(), myfunction);
//Output
for (int i=0; i < myvector.size(); i++)
seeout(myvector[i]);
}
int main() {
special obj;
obj.dostuff();
system("pause>nul");
}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Watch the magic disappearing act... if "myfunction" is inside the class, the errors are right here before your eyes! Take it out of the class and they vanish into thin air! HOW DO THEY DO IT!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Don't believe everything you read (or think you read) on the Internet. Not until you have confirmed it elsewhere at least. Apply Occam's razor - consider this; the STL was designed and developed by people probably a lot smarter than you or I; it has been used for years successfully in tens of thousands of applications; if it were so badly designed, do you think someone would have noticed before you? The conclusion you must draw then is that you are missing something or doing something wrong.
I really have no idea why you think that this is such a dead end since there is no good reason at all why you should place myfunction() in class special!
Now, the problem that appears to confound you is that a pointer to a member function, does not behave like a pointer to a non-member function. Well, of course not; how could it? A member function may reference data belonging to an object or instance of the class. A normal pointer to a function is simply an entry point address, the function would have no way of determining where its data were. This has nothing to do with the STL, that is how C++ works.
Now in your case, "class special" has no data. Which kind of begs the question why it need be a class? If this is just a way of collecting functions in a group, then a namespace would be more appropriate, but just plain ordinary functions will do. If you have a good reason for putting it in a class (which is not evident in teh example code), then since it does not access data, you can simply declare it static, then it will behave like a normal function pointer:
class special {
public:
static bool myfunction(person i, person j);
static void seeout(person out);
static void dostuff();
};
As you can see this brings no real benefit that a namespace could not be used for, e.g.:
namespace special {
bool myfunction(person i, person j);
void seeout(person out);
void dostuff();
};
but to be honest there may be no real benefit there either. One thing you may need to do in some cases is declare the compare function as a friend of the class being compared so that it can have access to private data (though in your case you have none). Another way however of organising this is to make the compare function a static member function of the class being compared - that way if it has private data that needs to be considered in the comparison, it also has access to it:
struct person
{
int age;
string name;
int weight;
static bool myfunction(person i, person j);
};
To be frank, this further begs teh question of why person is a struct and not a class? Perhaps
class person
{
private :
int age;
string name;
int weight;
public :
static bool myfunction(person i, person j);
void seeout();
void dostuff();
};
Note how seeout() no longer needs to take a paramater since it can now operate on the object of which it is a member. It would be defined thus:
void special::seeout()
{
cout << name << ": " << age << " years, " << weight << " lbs." << endl;
}
You would of course need access functions for getting and setting private members and a constructor for initialisation perhaps. The benefit being that such functions can perform validation, and in debug a break point on an access an function will trap all accesses. To do that with public data members may require many breakpoints to be set, and you may still not get those that access indirectly through references or pointers.
In essence your problem is not with the STL but rather with your lack of understanding of Object Oriented Programming. However solving that is a longer haul, for the timebeing your immediate problem is easily fixed.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi, do any of you know a way to refer to members of a struct abstractly?
For instance, with the given struct:
struct person {
int age;
string name;
int height;
}
I want to do something like
person jim;
cout << jim.1; //displays age
This is important to me because i have a program with an array of structs. I want to sort this array by any of the member criterias. I.e. with the sample struct given above, an array of people could be sorted by age, name, or height. I do NOT want to have to write multiple sort functions for each member. Is there any way to refer to these struct members abstractly?
First... euck! I cant help thinking that whatever you are trying to do, this is a nasty way of doing it.
You don't need to write "multiple sort functions" in any case. Consider using the C library's qsort() function, then all you need is a compare function for each member (either way you need a different function for each member because they are different types!):
struct person
{
int age;
string name;
int height;
static int cmpAge( void a, void b)
{
return (person)b->age - (person)a->age
}
static int cmpName( void a, void b)
{
return (((person)a->name < (person)b->name) ? -1 : (((person)a->name > (person)b->name) ? 1 : 0)) ;
}
static int cmpHeight( void a, void b)
{
return (person)b->height - (person)a->height
}
}
Then to sort by name for example:
qsort( peopleArray, numPeople, person::cmpName ) ;
This is actually quite a cumbersome method, a far better way would be to use an STL container class rather than an array. That would enable you to use the STL <algorithms> sort function. This still requires you to write comparison functions - there is no getting away from that - however the comparison functions are simpler, because they only return two states (true/false).
http://www.cplusplus.com/reference/clibrary/cstdlib/qsort.html
http://www.cplusplus.com/reference/stl/
http://www.cplusplus.com/reference/algorithm/sort.html
Clifford
Clifford, Clifford seriously, i could kiss you. I never knew the STL had that sort functionality. You just single-handedly solved my problem and optimized my code immensely with the same solution.
Except i had a problem implementing it. In a test file, everything worked great. Now that i implement it into a function of a class, it gives me these errors:
97 C:\Documents and Settings\Aspire II\Desktop\structreadwrite.cpp no matching function for call to 'sort(gnu_cxx::normal_iterator<employee, std::vector<employee, std::allocator<employee> > >, gnu_cxx::normal_iterator<employee, std::vector<employee, std::allocator<employee> > >, <unknown type>)'
note C:\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h:2578 candidates are: void std::sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = gnu_cxx::normal_iterator<employee, std::vector<employee, std::allocator<employee> > >, _Compare = bool (EmployeeSet::)(employee, employee)]
May i send you the code via e-mail? (I know, i know, i shouldn't be using an address with spaces in it, but i don't think that's causing the problem)
Found on another forum: You can't use sort with member functions. Period. There are more technical details to this, but they really don't matter. What's the point of an implementation like this that can't handle classes? The STL wasn't built in the 80s or anything. Oh well. Thanks anyway, Clifford.
I have narrowed down the problem. It can be shown with the given code:
include <iostream>
include <string>
include <algorithm>
include <vector>
using namespace std;
struct person {
int age;
string name;
int weight;
};
class special {
public:
bool myfunction(person i, person j);
void seeout(person out);
void dostuff();
};
bool special::myfunction(person i, person j) {
return i.weight<j.weight;
}
void special::seeout(person out) {
cout << out.name << ": " << out.age << " years, " << out.weight << " lbs." << endl;
return;
}
void special::dostuff() {
//Create a vector of structs and load it
vector<person> myvector;
person jim = {22,"jim",175};
person frank = {23,"frank",500};
person hank = {25,"hank",222};
myvector.push_back(jim);
myvector.push_back(frank);
myvector.push_back(hank);
//Call STL's sort THIS LINE CAUSES THE ERROR
sort (myvector.begin(), myvector.end(), myfunction);
//Output
for (int i=0; i < myvector.size(); i++)
seeout(myvector[i]);
}
int main() {
special obj;
obj.dostuff();
system("pause>nul");
}
Watch the magic disappearing act... if "myfunction" is inside the class, the errors are right here before your eyes! Take it out of the class and they vanish into thin air! HOW DO THEY DO IT!
Don't believe everything you read (or think you read) on the Internet. Not until you have confirmed it elsewhere at least. Apply Occam's razor - consider this; the STL was designed and developed by people probably a lot smarter than you or I; it has been used for years successfully in tens of thousands of applications; if it were so badly designed, do you think someone would have noticed before you? The conclusion you must draw then is that you are missing something or doing something wrong.
I really have no idea why you think that this is such a dead end since there is no good reason at all why you should place myfunction() in class special!
Now, the problem that appears to confound you is that a pointer to a member function, does not behave like a pointer to a non-member function. Well, of course not; how could it? A member function may reference data belonging to an object or instance of the class. A normal pointer to a function is simply an entry point address, the function would have no way of determining where its data were. This has nothing to do with the STL, that is how C++ works.
Now in your case, "class special" has no data. Which kind of begs the question why it need be a class? If this is just a way of collecting functions in a group, then a namespace would be more appropriate, but just plain ordinary functions will do. If you have a good reason for putting it in a class (which is not evident in teh example code), then since it does not access data, you can simply declare it static, then it will behave like a normal function pointer:
class special {
public:
static bool myfunction(person i, person j);
static void seeout(person out);
static void dostuff();
};
then:
sort (myvector.begin(), myvector.end(), special::myfunction);
As you can see this brings no real benefit that a namespace could not be used for, e.g.:
namespace special {
bool myfunction(person i, person j);
void seeout(person out);
void dostuff();
};
but to be honest there may be no real benefit there either. One thing you may need to do in some cases is declare the compare function as a friend of the class being compared so that it can have access to private data (though in your case you have none). Another way however of organising this is to make the compare function a static member function of the class being compared - that way if it has private data that needs to be considered in the comparison, it also has access to it:
struct person
{
int age;
string name;
int weight;
static bool myfunction(person i, person j);
};
To be frank, this further begs teh question of why person is a struct and not a class? Perhaps
class person
{
private :
int age;
string name;
int weight;
public :
static bool myfunction(person i, person j);
void seeout();
void dostuff();
};
Note how seeout() no longer needs to take a paramater since it can now operate on the object of which it is a member. It would be defined thus:
void special::seeout()
{
cout << name << ": " << age << " years, " << weight << " lbs." << endl;
}
You would of course need access functions for getting and setting private members and a constructor for initialisation perhaps. The benefit being that such functions can perform validation, and in debug a break point on an access an function will trap all accesses. To do that with public data members may require many breakpoints to be set, and you may still not get those that access indirectly through references or pointers.
In essence your problem is not with the STL but rather with your lack of understanding of Object Oriented Programming. However solving that is a longer haul, for the timebeing your immediate problem is easily fixed.
Clifford