how to sort elements by one measure
In C++ I don't quite understand how to sort elements, by defining a custom function.
Cppreference.com says that for开发者_运维知识库 the comparison function:
comp - comparison function which returns true if the first argument is less than the second.
bool cmp(const Type1 &a, const Type2 &b);
Naturally I would think that for sorting elements I would need to define a measure, and the sort function would sort them depending on the measure.
In my actual example I would like to sort image files depending on how far they are from a camera. I have a vector of boost::filesystem::path linking to directories of image sequences
vector<boost::filesystem::path> path_vec
and I would naturally think that I need to write a function like
double z_distance( boost::filesystem::path filename, integer time )
what would return a double for all the elements and sort them in ascending or descending order for every frame (thus the changing time in the argument).
Can you tell me how should I turn this function which returns a single value, into a bool function needed for the sort function?
And how could I pass arguments, if I can only pass a function name, not a full call to a function?
When you define
bool nearer(const boost::filesystem::path& a, const boost::filesystem::path& b)
{
int somevalue = 0;
return z_distance(a, somevalue) < z_distance(b, somevalue);
}
you can do
std::sort(path_vec.begin(), path_vec.end(), nearer);
However, I don't know what to do with the second argument of your function z_distance()
. Maybe you can get it from your files or you have to use a functor instead of a function to compare. For functor see the answer @templatetypedef gave.
Since you tagged VC++10, you can also use a C++0x feature: write a lambda expression (an adhoc function) to pass arguments:
int somevalue = 0;
std::sort(path_vec.begin(), path_vec.end(),
[=](const boost::filesystem::path& a, const boost::filesystem::path& b) -> bool
{
return z_distance(a, somevalue) < z_distance(b, somevalue);
}
);
There are many ways that you can do this.
If you happen to know that the second argument to z_distance
is always going to be some fixed value, then you could convert the function into a comparator by writing an auxiliary function that actually does the comparison. For example:
bool CompareByDistance(const boost::filesystem::path& lhs,
const boost::filesystem::path& rhs) {
return z_distance(lhs, kSecondArg) < z_distance(rhs, kSecondArg);
}
If you don't know what the second parameter to the z_distance
function should be, or it can only be determined at runtime, then you may need to use a function object. A function object (sometimes called a functor) is an object that mimics a regular function. You can invoke it by passing in some number of parameters, but because it's an object the function that ends up getting called can access local state in addition to the parameters. One such function object you could build might look like this:
class CompareByDistance {
public:
/* Constructor takes in the time that you want to sort at,
* then stores it for later.
*/
CompareByDistance(int time) : mTime(time) {
}
/* This is the function call operator that is called when you try
* treating a CompareByDistance object as a function. Note how it
* uses the mTime field as a parameter to `z_distance`.
*/
bool operator()(const boost::filesystem::path& lhs,
const boost::filesystem::path& rhs) const {
return z_distance(lhs, mTime) < z_distance(rhs, mTime);
}
private:
const int mTime; // Store mTime for later
};
Now, if you wanted to sort everything at some time t, you could write
sort(elems.begin(), elems.end(), CompareByDistance(t));
For more info on functors, and as a shameless plug, here's a chapter on functors that I wrote for a C++ course I taught a year ago.
Hope this helps!
Overload the operator<
to return &A < &B, and sort should work with just begin(), end() and nothing else.
So
bool operator<(const SomeType& a, const SomeType& b)
{
return z_distance(a, 0) < z_distance(b, 0);
}
And you should be able to call it like this.
std::vector<SomeType> vec;
std::sort(vec.begin(), vec.end());
Okay, here's where you're confused...
The function compares two elements at a time, readjusting the internal container (tree or whatever) based on the result. So, all C++ needs to know in the STL functions is is elmement A less than element B based on your function.
So, for all you care your comparison function can compare their distances, first names of people, or whatever the heck you want. The function just has to return true if one element is less than the other, and C++ will handle how to sort with it.
精彩评论