There is a simple example of the class Test
#include <algorithm>
#include <iterator>
#include <vector>
template <typename T>
struct MinMax { T min, max; };
template <typename T>
using TList = std::vector<T>;
template <typename T>
class Test
{
private:
const T a, b;
const MinMax <T> m;
public:
Test() : a(0), m{ 0, 0 }, b(0.0) {};
public:
T getA() const { return a; }
MinMax <T> & getMinMax() const { return m; }
T getB() const { return b; }
Test(const Test &t) : a(t.a), b(t.b), m(t.m ) {}
};
with the constant data members. Instead of the constructor, the data are not changed. I would like to copy the vector of Test objects to another vector using std::inserter. I am surprised that the copy constructor is not sufficient
int main()
{
TList <Test <double> > t1;
TList <Test <double> > t2;
Test<double> t;
t1.push_back(t);
std::copy(t2.begin(), t2.end(), std::inserter(t1, t1.begin()));
return 0;
}
and the following compiler error appears (VS2015):
Error C2280 'Test<double> &Test<double>::operator =(const Test<double> &)': attempting to reference a deleted function Const
Is it possible to let the data members const and perform a copy in a different way (some hack :-))? Or an operator = must be defined, so the data members cannot be const (it is imppossible to assign to an object with const data members)?
Thanks for your help.
An insert to a vector reassigns all elements after the inserted element and assigns the inserted element to the freed up slot.
In other words, you can't because the Standard requires the elements of standard containers to be Asssignable (have a = b defined) to offer full functionality.
Apart from the obvious solution of writing your own operator= you can also add elements with const members to a vector by pushing back:
std::copy(t2.begin(), t2.end(), std::back_inserter(t1));
but that's kind of working against the Standard; push_back doesn't happen to need assignability but other functions may.
Or, you can use a container that doesn't require assignability to insert, e.g.:
template <typename T>
using TList = std::list<T>;
trading off all the benefits of contiguous memory cache locality of a vector.
On a closing note, I tend to avoid declaring data members of my structures const because of such problems with generic containers that require assignability under the hood. Notice that in your example removing const from private members would leave you with good-enough read-only fields (that can be accessed only via getters from outside).
Related
I have a class A containing a vector of shared_ptr<B>.
I implemented a getter to this vector.
In some cases, it would be nice to ensure that the content in B does not change (make B read only or a const reference).
If I would not have used vector<shared_ptr<B>> but rather vector<B> I could simply write two getters, one returning a const reference (read only), and one returning a reference only (manipulation possible). #
Is there a way to do the same thing with a vector<shared_ptr<B>>?
Maybe it is easier to understand the problem in this code:
#include <vector>
#include <memory>
using namespace std;
class B{
public:
explicit B(int i) : i_{i} {}
void set_i(int i){i_ = i;}
private:
int i_ = 0;
};
class A{
public:
const vector<shared_ptr<B>> &get_vb(){return vb;}
// const vector<shared_ptr<const B>> &get_vb_const(){return vb;} // I would like to return a const vector with const elements in some cases
private:
vector<shared_ptr<B>> vb{make_shared<B>(1), make_shared<B>(10), make_shared<B>(100)};
};
int main() {
A a;
const auto &vb = a.get_vb();
vb[0]->set_i(2);
// const auto &vb_const = a.get_vb_const(); // somehow I would like to gain this vector without being able to modify the elements
// vb_const[0]->set_i(2); // should throw error
return 0;
}
You need to construct a new vector with the desired elements:
const vector<shared_ptr<const B>> get_vb_const() const {
return vector<shared_ptr<const B> > {vb.cbegin(), vb.cend()};
}
Note that the function doesn't return a reference now because we are creating a temporary and returning it.
transform vector of shared_ptr with non const elements to vector of shared_ptr with const elements
You can use the constructor of vector that accepts a pair of iterators to perform the conversion.
You can avoid the overhead of allocating and copying a vector by implementing a custom const iterator for your class.
I am writing a vector class and I would like it to have the following characteristics:
Use static allocation on the stack whenever possible (to avoid calling new for efficiency).
Be able to be instantiated from a pointer if the user prefers to provide a previously allocated array.
The class needs to be easily converted to a simple pointer. This allows to use previously written routines in C.
Find below this simple test problem with the solution I came up with. I use inheritance so Vector inherits from Vector_base which provides a common interface (pure virtual) for all vectors.
Then I define an empty class Vector that allows me then using partial specialization to have different storage schemes; static or dynamic.
The idea behind this is that I just want vector to be a C++ wrapper to the old-fashioned static array.
I like the implementation below. I'd like to keep the interface I came up with in main.
What I don't like is that sizeof(Vector3) = 32 when in C a vector of three doubles is 24 bytes. The reason for this is the extra 8 bytes of the virtual table.
My question: can I somehow come up with another design that would provide me with the same interface but the vector only has 24 bytes?
Summarizing:
I'd like have a Vector3 of 24 bytes, as in C.
I still want to have arbitrarily large vectors though (with <double,n>)
I'd like to keep the interface used in main().
Could I use a programming idiom like traits or polices for this? I am very new to those and I don't know if they could provide a solution.
Find my little test code below:
#include <iostream>
using namespace std;
#define TRACE0(a) cout << #a << endl; a;
#define TRACE1(a) cout << #a "=[" << a << "]" << endl;
enum alloc_type {Static,Dynamic};
template <class T>
class Vector_base{
public:
Vector_base(){}
virtual operator T*() = 0;
virtual T operator[](int i)const = 0;
virtual T& operator[](int i) = 0;
virtual int size() const = 0;
friend ostream& operator<<(ostream &os,const Vector_base& v){
for (int i=0; i<v.size(); i++)
cout << v[i] << endl;
return os;
}
};
// base template must be defined first
template <class T, int n,alloc_type flg=Static>
class Vector{};
//Specialization for static memory allocation.
template <class T, int n>
class Vector<T,n,Static>: public Vector_base<T>{
public:
T a[n];
public:
Vector() {
for (int i=0; i<n; i++) a[i] = 0;
}
int size()const{return n;}
operator T*(){return a;}
T operator[](int i)const {return a[i];}
T& operator[](int i){return a[i];}
};
//Specialization for dynamic memory allocation
template <class T,int n>
class Vector<T,n,Dynamic>: public Vector_base<T>{ //change for enum. flg=0 for static. flg=1 for dynamic. Static by default
public:
T* a;
public:
Vector():a(NULL){
}
Vector(T* data){ //uses data as its storage
a = data;
}
int size()const{return n;}
operator T*(){return a;}
T operator[](int i)const {return a[i];}
T& operator[](int i){return a[i];}
};
//C++11 typedefs to create more specialized three-dimensional vectors.
#if (__cplusplus>=201103L)
template <typename Scalar,alloc_type flg=Static>
using Vector3 = Vector<Scalar,3,flg>;
#else
#error A compiler with the C++2011 standard is required!
#endif
int main(){
cout << "Testing Vector3: " << endl;
//Vector<double,3> v3;
Vector3<double> v3;
TRACE0(cout << v3 << endl;);
TRACE1(sizeof(v3));
//Vector<double,3,Dynamic> v0(v3);
Vector3<double,Dynamic> v0(v3); //calls Vector<double,3,Dynamic>::Vector(double*) and uses the conversion operator on v3.
TRACE1(sizeof(v0));
TRACE1(sizeof(double*));
TRACE0(v3[1] = 2.1;);
TRACE0(cout << v0 << endl;);
return 0;
}
All the features you want are offered as Standard or can be plugged in to existing Standard extension points.
Use static allocation on the stack whenever possible (to avoid calling new for efficiency).
Meet std::array<T, N>. It's a C++ wrapper on a C array and presents all the same characteristics.
Be able to be instantiated from a pointer if the user prefers to provide a previously allocated array.
Meet Allocators. You can code an allocator that meets the requirement that gives back already allocated memory, then simply use std::vector. Such an allocator is under consideration for future Standards along with other allocator enhancements like polymorphic allocators.
The class needs to be easily converted to a simple pointer. This allows to use previously written routines in C.
Both std::vector and std::array offer this as a triviality.
If you want to offer this choice at runtime, consider boost::variant. Rolling your own discriminated union- not advised.
If I understand you correctly, something like LLVM's SmallVector seems to fit the bill. It has a template parameter declaring the maximum size you want allocated on the stack, and switches to heap memory only when it grows outside that range.
If it doesn't fit your interface directly, I'm sure looking at the implementation will be very useful towards writing something similar yourself.
You are talking about two policies for locating the data: either inline as a small-array optimization, or via indirection with a pointer to a dynamically allocated buffer.
There are two ways to make that policy choice: With static type information, or dynamically. The dynamic choice requires storage to indicate whether any particular vector uses the static or dynamic policy.
For a vector of doubles, you can perhaps use an illegal value in the first element (a NaN encoding) to indicate that the dynamic policy is in effect (the pointer needs to be stored overlapping the remaining elements, use a union for this).
But in other data types, all possible bit patterns are valid. For those you will require additional storage to select the policy. You might know for a particular problem that a particular bit isn't needed for the range of values, and can be used as a flag. But there's no general solution applicable to all data types.
You probably want to look at implementations of the "small string optimization". They are making the same tradeoff for improved locality of reference when the data is small enough to store directly inside the object, and also generally trying to avoid using mode space than necessary.
One thing is for sure. In order to avoid significantly increase in space requirements, you're going to need close coupling. No specialization, no inheritance, just one monolithic class that implements both policies.
Ok guys. It took me all day but this is the solution I came up with and it does exactly what I want. Please share your comments and suggestions to this solution.
Of course I didn't implement all methods I want. I only implemented two fake dot products to show how specific C implementations are chosen at compile time by use of templates.
The scheme is quite more complex than what I thought it would be. The basic concepts I'm using to accomplish my design requirements are:
the curiously recurring template pattern.
Partial specialization
Traits
Compile-time selection with templates (see how I decide what dot product implementation to use).
Again, thanks and please comment!! See code below
#include <iostream>
using namespace std;
#include <type_traits>
//C++11 typedefs to create more specialized three-dimensional vectors.
#if (__cplusplus<201103L)
#error A compiler with the C++2011 standard is required!
#endif
template<class T>
struct traits{};
#define TRACE0(a) cout << #a << endl; a;
#define TRACE1(a) cout << #a "=[" << a << "]" << endl;
enum {Dynamic = -1};
template<typename T,int n>
struct mem_model{
typedef T array_model[n];
};
//Specialization to Dynamic
template<typename T>
struct mem_model<T,Dynamic>{
typedef T* array_model;
};
template<class derived_vector>
struct Vector_base: public traits<derived_vector>{ //With traits<derived_vector> you can derive the compile time specifications for 'derived_vector'
typedef traits<derived_vector> derived;
typedef typename traits<derived_vector>::Scalar Scalar;
public:
inline int size()const{ //Calling derived class size in case a resize is done over a dynamic vector
return static_cast<const derived_vector*>(this)->size(); //derived_vector MUST have a member method size().
}
inline operator Scalar*(){return a;} //All vectors reduce to a Scalar*
inline bool IsStatic()const{return (n==Dynamic)? false: true;}
inline int SizeAtCompileTime()const{return n;} //-1 for dynamic vectors
protected:
using derived::n; //compile time size. n = Dynamic if vector is requested to be so by the user.
typename mem_model<Scalar,n>::array_model a; //All vectors have a Scalar* a. Either static or dynamic.
};
//Default static
template<typename Scalar,int n>
class Vector:public Vector_base<Vector<Scalar,n> >{ //Vector inherits main interface from Vector_base
public:
//Constructors
Vector(){
//do nothing for fast instantiation
}
Vector(const Scalar& x,const Scalar& y,const Scalar& z){
a[0] = x; a[1] = y; a[2] = z;
}
//
inline int size()const{return n;}
private:
using Vector_base<Vector<Scalar,n> >::a;
};
//Traits specialization for Vector. Put in an inner_implementation namespace
template<typename _Scalar,int _n>
struct traits<Vector<_Scalar,_n> >{
typedef _Scalar Scalar;
enum{
n = _n
};
};
double clib_dot_product_d(const int n,double* a,double* b){
double dot = 0.0;
for(int i=0;i<n;i++)
dot += a[i]*b[i];
return dot;
}
float clib_dot_product_f(const int n,float* a,float* b){
cout << "clib_dot_product_f" << endl;
return 1.0;
}
template<typename Scalar>
struct dot_product_selector{};
template<>
struct dot_product_selector<double>{
template<class derived1,class derived2>
static double dot_product(Vector_base<derived1> &a,Vector_base<derived2> &b){
return clib_dot_product_d(a.size(),a,b);
}
};
template<>
struct dot_product_selector<float>{
template<class derived1,class derived2>
static float dot_product(Vector_base<derived1> &a,Vector_base<derived2> &b){
return clib_dot_product_f(a.size(),a,b);
}
};
template<class derived1,class derived2>
typename Vector_base<derived1>::Scalar dot_product(Vector_base<derived1> &a,Vector_base<derived2> &b){
//run time assert checking the two sizes are the same!!
//Compile time (templates) check for the same Scalar type
static_assert( std::is_same<typename Vector_base<derived1>::Scalar,typename Vector_base<derived2>::Scalar>::value,"dot product requires both vectors to have the same Scalar type");
return dot_product_selector<typename Vector_base<derived1>::Scalar>::dot_product(a,b);
}
#if 0
template <typename Scalar,alloc_type flg=Static>
using Vector3 = Vector<Scalar,3,flg>;
#endif
int main(){
cout << "Testing Vector3: " << endl;
Vector<double,3> as;
Vector<double,Dynamic> ad;
TRACE1(sizeof(as));
TRACE1(sizeof(ad));
TRACE1(as.SizeAtCompileTime());
TRACE1(ad.SizeAtCompileTime());
Vector<double,3> u(1,2,3),v(-1,1,5);
Vector<float,3> uf,vf;
TRACE1(dot_product(u,v));
dot_product(uf,vf);
//dot_product(u,vf); //this triggers a compile time assertion using static_assert
return 0;
}
You could simplify the Vector template specialization to...
template <class T, std::size_t Size = -1>
class Vector {
// The statically allocated implementation
};
template <class T>
class Vector<T, -1> {
// The dynamically allocated implementation
};
The implementations could possibly be thin wrappers around std::vector and std::array.
EDIT: This avoid the magic constant...
template<typename T = void>
class Structure {};
template<typename T, std::size_t Size>
class Structure<T[Size]> {
T data[Size];
// The statically allocated implementation
};
template<typename T>
class Structure<T[]> {
T * pData;
public:
Structure(std::size_t size) : pData(new T[size]) {}
~Structure() { delete[] pData; }
// The dynamically allocated implementation
};
Instantiated like this...
Structure<int[]> heap(3);
Structure<int[3]> stack;
EDIT: Or use policies like so...
class AllocationPolicy {
protected:
static const std::size_t Size = 0;
};
template<std::size_t Size_>
class Static : AllocationPolicy {
protected:
static const std::size_t Size = Size_;
};
class Dynamic : AllocationPolicy {
protected:
static const std::size_t Size = 0;
};
template <typename T, typename TAllocationPolicy = Dynamic>
class Vector : TAllocationPolicy {
static_assert(!std::is_same<typename std::remove_cv<TAllocationPolicy>::type, AllocationPolicy>::value && std::is_base_of<AllocationPolicy, TAllocationPolicy>::value, "TAllocationPolicy must inherit from AllocationPolicy");
using TAllocationPolicy::Size;
public:
T data[Size];
};
template <typename T>
class Vector<T, Dynamic> : private Dynamic {
T * data;
public:
Vector(std::size_t size) : data(new T[size]) {}
~Vector() { delete [] data; }
};
I'm trying to learn more about templates and have come across a problem I can't seem to solve. At the moment the class below works fine.
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
template <class T, int s>
class myArray{
public:
T* data;
inline T& operator[](const int i){return data[i];}
myArray(){
data=new T[s];
}
myArray(const myArray& other){
data=new T[s];
copy(other.data,other.data+s,data);
}
myArray& operator=(const myArray& other){
data=new T[s];
copy(other.data,other.data+s,data);
return *this;
}
~myArray(){delete [] data;}
};
If I use it:
myArray<myArray<myArray<int,10>,20>,30> a;
a is now 30x20x10 array that I can access with the normal array brackets e.g. a[5][5][5]. I wish to add a feature so that I could write:
myArray<myArray<myArray<int,10>,20>,30> a(10);
and initialise all of the entries to 10 for example. I can't work out how to do this. As I understand, each layer of myArray is constructed using the default constructor. If I changed this to something like:
myArray(int n=0){
data=new T[s];
fill(data,data+s,n); //T might not be of type int so this could fail.
}
I think this should fail when data is not of type int (i.e. on any array on dimensions > 1), however it doesn't. It works when the array is square, but if not then some of the entries aren't set to 10. Does anyone have an idea how the standard vectors class achieves this? Any help would be amazing. Thanks!
Well, try something like this:
myArray()
: data(new T[s]()) // value-initialization!
{
}
myArray(T const & val)
: data(new T[s]) // default-initialization suffices
{
std::fill(data, data + s, val);
}
If you're into variadic templates, you might cook up something even more grotesque involving variadically filled initializer lists, but I think we've done enough learning for one week.
Note the fundamental flaw in using new: Either version requires that your class T can be instantiated in some "default" state, and that it be assignable, even though we never require the default state in the second version. That's why "real" libraries separate memory allocation and object construction, and you never see a new expression unless its the placement version.
std::vector uses placement new on memory blocks. It constructs the data.after allocating the memory in a second line of code.
This technique would work for you as well. Be careful with placement new as it requires you to call destructors manually as well.
Here is a half-assed route without placement new:
template<typename U>
explicit MyArray( U const& constructFromAnythingElse )
{
AllocateSpace(N); // write this, just allocates space
for (int i = 0; i < N; ++i)
{
Element(i) = T( constructFromAnythingElse );
}
}
with placement new, you have to allocate the memory first, then construct in-place, and then remember to destroy each element at the end.
The above is half-assed compared to a placement new route, because we first construct each element, then build another one, and use operator= to overwrite it.
By making it a template constructor on an arbitrary type, we don't rely on multiple conversion to get multiple levels down into the array. The naive version (where you take a T const&) doesn't work because to construct an array of arrays of arrays of T, the outermost one expects an array of arrays of T as an argument, which expects an array of T as an argument, which expects a T -- there are too many levels of user defined construction going on there.
With the above template constructor, the array of array of array of T accepts any type as a constructor. As does the array of array of T, as does the array of T. Finally, the T is passed in whatever you constructed the outermost array of array of array of T, and if it doesn't like it, you get a compiler error message that is nearly completely unreadable.
Make specialization for arrays containing other arrays. To do this you need some common implementation class to be used in general and specialized MyArray:
Common implementation (I made some fixes for you - see !!! comments):
template <class T, int s>
class myArrayImpl {
public:
T* data;
T& operator[](int i){return data[i];} //!!! const before int not needed
const T& operator[](int i) const {return data[i];} //!!! was missing
myArrayImpl(){
data=new T[s]();
}
myArrayImpl(const myArrayImpl & other){
data=new T[s];
copy(other.data,other.data+s,data);
}
myArrayImpl& operator=(const myArrayImpl& other){
T* olddata = data; // !!! need to store old data
data=new T[s];
copy(other.data,other.data+s,data);
delete [] olddata; //!!! to delete it after copying
return *this;
}
~myArrayImpl(){delete [] data;}
};
Then make general implementation - note the definition of value_type and setAll:
template <class T, int s>
class myArray : private myArrayImpl<T,s> {
typedef myArrayImpl<T,s> Impl;
public:
using Impl::operator[];
myArray() : Impl() {}
typedef T value_type; // !!!
explicit myArray(const value_type& value) {
setAll(value);
}
void setAll(const value_type& value) {
fill(this->data, this->data + s, value);
}
};
And the specialized version for myArray of myArray - see also differences in value_type and setAll:
template <class T, int s1, int s2>
class myArray<myArray<T,s2>,s1> : private myArrayImpl<myArray<T,s2>,s1> {
typedef myArrayImpl<myArray<T,s2>,s1> Impl;
public:
using Impl::operator[];
myArray() : Impl() {}
typedef typename myArray<T,s2>::value_type value_type; // !!!
explicit myArray(const value_type& value) {
setAll(value);
}
void setAll(const value_type& value) {
for_each(this->data, this->data + s1, [value](myArray<T,s2>& v) { v.setAll(value); });
}
};
And usage:
int main() {
myArray<myArray<myArray<int,7>,8>,9> a(7);
std::cout << a[0][0][0] << std::endl;
std::cout << a[8][7][6] << std::endl;
}
Full example here: http://ideone.com/0wdT9D
I'm having some trouble with a template struct.
template<typename T>
struct A{
const int v1;
T* v2;
};
My purpose is to make v1 always not editable, while v2 should be editable if I use T and not editable if I use const T as type.
If I create constructor to initialize A, the struct becomes:
template<typename T>
struct A{
const int v1;
T* v2;
A() : v1(-1) { v2=NULL; }
A(int value) : v1(value) { v2=NULL; }
};
But then g++ says that I need a specific assignment operator:
error: non-static const member ‘const int A::v1’, can’t use default assignment operator
But my assignment operator should also allow editing of v1. The only thing I'd like to avoid is an edit from the outside, something like:
A a;
a.v1=10;
Is there any way to implement this (without creating getter/setter or using a pointer to a new A(int) with the desired value)?
What if I declare v1 as a const int * ? It could refer someway to some value, but it cannot edit it.
Here's a way to "expose" a public, read-only data member that is modifiable by the class's own member functions (including assignment):
template <typename T>
class Helper {
friend class A;
T *ptr;
Helper &operator=(const Helper &rhs) = default; // in C++11
Helper &operator=(const Helper &rhs) { ptr = rhs.ptr; } // in C++03
public:
Helper(T *ptr) : ptr(ptr) {}
operator const int &() const { return *ptr; }
};
class A {
int v1_;
public:
Helper<int> v1;
A() : v1(&v1_) {} // although `A` should have a constructor that sets `v1_`
A(const A &rhs) { v1_ = rhs.v1_; v1 = Helper<int>(&v1_); }
A &operator=(const A &rhs) { v1_ = rhs.v1_; v1 = Helper<int>(&v1_); }
};
Now anyone outside the class A can use v1, but the only thing they can use it for is to get a const int& reference to v1_.
It is far easier just to give A a getter function that returns const int &, but if you really want the data member syntax then this provides it...
It says that you cannot use the default assignment operator. Nothing keeps you from writing your own operator= and use a const_cast. Unfortunately, this will be undefined behavior as v1 is declared const. So I'd suggest that you use accessors and private data.
You could just make it a class with everything public (thats all a struct is) and use an initialisation list - no need for getters/setters
I solved my problem by changing the type of v1 from int to const int *, by doing this I can change the address of v1 and consequently change the value that v1 points to, but preventing any kind of editing.
So, here's my new simple struct
template<typename T>
struct A{
const int* v1;
T* v2;
};
When I use A with type T, I let v2 to be edited, and when I use A with type T const I prevent any attempt to edit v2's pointed value.
My priority queue declared as:
std::priority_queue<*MyClass> queue;
class MyClass {
bool operator<( const MyClass* m ) const;
}
is not sorting the items in the queue.
What is wrong? I would not like to implement a different (Compare) class.
Answer summary:
The problem is, the pointer addresses are sorted. The only way to avoid this is a class that 'compares the pointers'.
Now implemented as:
std::priority_queue<*MyClass, vector<*MyClass>, MyClass::CompStr > queue;
class MyClass {
struct CompStr {
bool operator()(MyClass* m1, MyClass* m2);
}
}
Give the que the Compare functor ptr_less.
If you want the ptr_less to be compatible with the rest of the std library (binders, composers, ... ):
template<class T>
struct ptr_less
: public binary_function<T, T, bool> {
bool operator()(const T& left, const T& right) const{
return ((*left) <( *right));
}
};
std::priority_queue<MyClass*, vector<MyClass*>, ptr_less<MyClass*> > que;
Otherwise you can get away with the simplified version:
struct ptr_less {
template<class T>
bool operator()(const T& left, const T& right) const {
return ((*left) <( *right));
}
};
std::priority_queue<MyClass*, vector<MyClass*>, ptr_less > que;
The operator <() you have provided will compare a MyClass object with a pointer to a MyClass object. But your queue contains only pointers (I think). You need a comparison function that takes two pointers as parameters.
All this is based on some suppositions - please post your actual code, using copy and paste.
Since your priority_queue contains only pointer values, it will use the default comparison operator for the pointers - this will sort them by address which is obviously not what you want. If you change the priority_queue to store the class instances by value, it will use the operator you defined. Or, you will have to provide a comparison function.
Not sure about the priority queue stuff because I've never used it but to do a straight sort, you can do this:
class A
{
friend struct ComparePtrToA;
public:
A( int v=0 ):a(v){}
private:
int a;
};
struct ComparePtrToA
{
bool operator()(A* a1, A* a2) {return a1->a < a2->a;}
};
#include <vector>
#include <algorithm>
int _tmain(int argc, _TCHAR* argv[])
{
vector<A*> someAs;
someAs.push_back(new A(1));
someAs.push_back(new A(3));
someAs.push_back(new A(2));
sort( someAs.begin(), someAs.end(), ComparePtrToA() );
}
Note the memory leaks, this is only an example...
Further note: This is not intended to be an implementation of priority queue! The vector is simply an example of using the functor I created to compare two objects via their pointers. Although I'm aware of what a priority queue is and roughly how it works, I have never used the STL features that implement them.
Update: I think TimW makes some valid points. I don't know why he was downvoted so much. I think my answer can be improved as follows:
class A
{
public:
A( int v=0 ):a(v){}
bool operator<( const A& rhs ) { return a < rhs.a; }
private:
int a;
};
struct ComparePtrToA
{
bool operator()(A* a1, A* a2) {return *a1 < *a2;}
};
which is cleaner (especially if you consider having a container of values rather than pointers - no further work would be necessary).