Reputation: 13575
I want to develop a container which can sort its element with its attribute access member functions, such as Name(). I want to use it as the following
SortedVector<T, &T::Name> v;
T t;
v.Add(t);
v.FindElementWithName("AName");
How to declare the template class? Thanks a lot.
Upvotes: 3
Views: 118
Reputation: 24892
Here's some code which does something pretty similar to what you want: provides sorting based on a "keygetter" from a single object rather than a comparator on two objects. A C++11x version using lambdas ought to be considerably cleaner (this is adapted from some old gcc 4.4 code).
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
#include <string>
#include <vector>
template <
typename T,
typename K
> struct sort_by_key_comparator {
sort_by_key_comparator(boost::function<K(const T&)> keygetter)
:_keygetter(keygetter){}
bool operator()(const T& a,const T& b) {
return (_keygetter(a)<_keygetter(b));
}
boost::function<K(T)> _keygetter;
};
// Sort an iterator range based on comparison of
// keys of type K retrieved from ojects of type T
template <
typename IT,
typename T,
typename K
> void sort_by_key(
IT first,
IT last,
boost::function<K(const T&)> keygetter
) {
sort_by_key_comparator<T,K> cmp(keygetter);
std::sort(first,last,cmp);
}
class data {
public:
data(int id,const std::string& txt)
:_id(id),_txt(txt){}
int get_id() const {return _id;}
const std::string& get_txt() const {return _txt;}
private:
int _id;
std::string _txt;
};
int main(int,char**) {
std::vector<data> v;
v.push_back(data(0,"d"));
v.push_back(data(3,"c"));
v.push_back(data(1,"b"));
v.push_back(data(2,"a"));
boost::function<int(const data&)> idkey=
boost::bind(&data::get_id,_1);
sort_by_key(v.begin(),v.end(),idkey);
for (size_t i=0;i<v.size();++i)
std::cout << v[i].get_id() << ", " << v[i].get_txt() << std::endl;
std::cout << std::endl;
boost::function<std::string(const data&)> txtkey=
boost::bind(&data::get_txt,_1);
sort_by_key(v.begin(),v.end(),txtkey);
for (size_t i=0;i<v.size();++i)
std::cout << v[i].get_id() << ", " << v[i].get_txt() << std::endl;
}
Interestingly, Python's sorting uses this "keygetter" style, while C++'s STL/std library has of course been based on two-object comparators. Scala helpfully provides both styles (via sortBy
and sortWith
).
Upvotes: 1
Reputation: 145269
There is no declaration that allows the simple usage that you envision unless you allow only one function result type.
With that restriction you can do e.g.
template< class Item, std::string (Item::*)() const >
class SortedVector;
But more generally (not supporting the simple notation) you can do
template< class Item, class Result, Result (Item::*)() const >
class SortedVector;
The main problem is anyway how to leverage the standard library's classes.
I think I would use a std::vector
for the storage and a std::map
for the sorting, maybe.
Upvotes: 2