I'm not very good with C++ but I'm trying to create a generic base class that can be extended to create a kind of dynamic enum. There may be way better ways to do this and I'm open to suggestions but my main question here is why am I getting the error C2338 The C++ Standard doesn't provide a hash for this type.
Base Enums Template Class
template <typename T>
class Enums
{
public:
BOOL HasValue(T enumValue) const
{
auto it = this->m_EnumPairs.find(enumValue);
return (it != this->m_EnumPairs.end());
}
const DWORD Count() const
{
return this->m_EnumPairs.size();
}
const DWORD &operator[](T enumValue) const
{
auto it = this->m_EnumPairs.find(enumValue);
if (it == this->m_EnumPairs.end())
return 0;
return it->second;
}
const DWORD GetVersionCode() const
{
return this->m_VersionCode;
}
static const DWORD Count(DWORD versionCode)
{
T derived(versionCode);
return derived.Count();
}
protected:
DWORD m_VersionCode;
Enums(DWORD versionCode) : m_VersionCode(versionCode), m_NextValue(0) { }
virtual ~Enums() { }
void Add(T enumValue)
{
for (auto it = this->m_EnumPairs.cbegin(); it != this->m_EnumPairs.cend(); it++)
{
if (it->first == enumValue)
throw std::exception("Enum key already defined");
if (it->second == this->m_NextValue)
throw std::exception("Enum value already exists");
}
this->m_EnumPairs[enumValue] = this->m_NextValue++;
}
void Add(T enumValue, DWORD value)
{
this->m_NextValue = value;
this->Add(valueName);
}
private:
std::unordered_map<T, DWORD> m_EnumPairs;
DWORD m_NextValue;
};
Derived Enums .h
namespace Test
{
typedef enum _Enum
{
EnumValue1,
EnumValue2,
EnumValue3,
EnumValue4,
EnumValue5,
EnumValue6,
EnumValue7,
EnumValue8
} Enum;
}
class DerivedEnum : public Enums<Test::Enum>
{
public:
DerivedEnum(DWORD versionCode);
~DerivedEnum();
};
Derived Enums .cpp
DerivedEnum::DerivedEnum(DWORD versionCode) : Enums(versionCode)
{
this->Add(Test::EnumValue1);
this->Add(Test::EnumValue2);
this->Add(Test::EnumValue3);
this->Add(Test::EnumValue4);
this->Add(Test::EnumValue5);
this->Add(Test::EnumValue6);
if (versionCode > 200)
this->Add(Blocks::EnumValue7);
this->Add(Blocks::EnumValue8);
}
DerivedEnum::~DerivedEnum()
{
}
Usage
Enums<DerivedEnum>::Count(250)
I'm know I'm doing something wrong, I just want to know what I'm doing wrong and how I can do something like Enums<DerivedEnum>::Count(250). The error centers around the static Count function and the error goes completely away when I remove the static function and the call to it.
EDIT
To answer a question asked in the comments: The usage of this would be to get the size or number of entries in the "enum". For example, if I needed to read a structure from a file and in that structure is an array of items:
struct DataFromFile
{
int flags;
int array[SIZE_OF_ENUM];
}
If I have different versions of this file that contain a different number of items in the array, I can use the "enum" class to determine how many bytes to read based on Enums<DerivedEnum>::Count(250). If that doesn't make sense, I'll try to clarify even further.
UPDATE
As ZDF said in the comments, changing unordered_map to map fixed the issue. unordered_map requires a hash function and the default does not know how to hash my custom class, map does not require a hash and therefore works perfect in this situation.
Related
What is the method to save and retrieve contents (to/from a disk file) of an object who has const member variables?
Or more specifically, const members demand an initialization at the creation time of the object. So, the retrieval of the content has to happen before the initializers (before { } of the constructor). If we are not minding the encapsulation, we can retrieve and create the object with parameters. How to do everything by keeping the data-hiding?
Compiler: C++ 14 and maybe beyond.
Instantiation of the object, filling the content and storing for next context.
{ //CODE BLOCK 1 : making of content and saving to a diskfile
Abcd abcd(65535,256,25);
//some operations on abcd
//save to disk
QFile abcdFile("abcd.lion");
abcdFile.open(QFile::WriteOnly);
abcd.serialize(abcdFile);
abcdFile.close();
}
using same object after taking from file.
{ //CODE BLOCK 2 : loading from file and continue in another context
QFile abcdFile("abcd.lion");
abcdFile.open(QFile::ReadOnly);
Abcd abcdNew(abcdFile);
abcdFile.close();
if(!abcdNew.isHealthy())
printf("abcd from hdd is NOT Healthy :(\n");
else
{
//doTheJob(abcdNew);
}
}
The class.
#include <QFile>
class Abcd
{
const bool _healthy;//true if properly initialized
//IMPORTANT: _healthy has to be the first member in the class.
//this is to execute its initializer list first
protected:
const long _rX;
const long _rY;
long _count;
public:
Abcd(const long refX,
const long refY,
const long count) :
_healthy(true),
_rX(refX), _rY(refY),
_count(count)
{
}
Abcd(QFile &src) :
_healthy(deserialize(src)),
//Hack. Actually the initialization happened by this statement.
//just keeping the below statements for the sake of syntactical correctness. :(
_rX(_rX), _rY(_rY)
//,_count(count)
{
}
virtual
~Abcd()
{
}
inline
bool isHealthy()
{
return _healthy;
}
bool serialize(QFile &dest)
{
if(dest.write((char *)&_rY,sizeof(_rY))!=sizeof(_rY)) return false;
if(dest.write((char *)&_rX,sizeof(_rX))!=sizeof(_rX)) return false;
if(dest.write((char *)&_count,sizeof(_count))!=sizeof(_count)) return false;
return true;
}
private:
bool deserialize(QFile &src)
{
if(src.read((char *)&_rY,sizeof(_rY))!=sizeof(_rY)) return false;
if(src.read((char *)&_rX,sizeof(_rX))!=sizeof(_rX)) return false;
if(src.read((char *)&_count,sizeof(_count))!=sizeof(_count)) return false;
return true;
}
};
Please suggest a better method. For this, I have introduced a ‘healthy’ status member as the first member in the declaration of the class. Also in deserialization, I am fooling the compiler by casting the const variable to char * pointer.
My suggestion will be to use a static member function of the class to retrieve the contents of the file from disk and construct an object after the contents have been retrieved successfully.
Instead of:
Abcd(QFile &src) :
Use
static Abcd deserialize(QFile& src);
and implement it as:
Abcd Abcd::deserialize(QFile& src)
{
long rX;
long rY;
long count;
if(src.read((char *)&rY, sizeof(rY)) != sizeof(rY)) throw false;
if(src.read((char *)&rX, sizeof(rX)) != sizeof(rX)) throw false;
if(src.read((char *)&count, sizeof(count)) != sizeof(count)) throw false;
return Abcd(rX, rY, count):
}
PS It's strange that you save _rY first and then _rX. There is nothing wrong, it's just strange.
My suggestion is to split up the logic of Abcd and serialization/deserialization into two classes.
Benefits:
no field _healthy as object is always valid by design.
class Abcd does only one job. Is free from any logic of storing (Single responsibility)
Few hints:
RVO is mandatory since c++ 17
const fields just make the object not copy/move assignable (unable to use with containers etc.). Simply properly use const correctness to ensure immutability.
do not inherit implementation, only interfaces: Abcd is final, no virtual methods - better performance.
follow the Cpp Core Guidelines
class Abcd final
{
public:
Abcd(const long refX, const long refY, const long count)
: _rX(refX)
, _rY(refY)
, _count(count)
{
}
long GetRX() const
{
return _rX;
}
long GetRY() const
{
return _rY;
}
long GetCount() const
{
return _count;
}
protected:
long _rX;
long _rY;
long _count;
};
#include <boost/optional.hpp>
#include <QFile>
template <typename T>
using Opt = boost::optional<T>; // or equivalent
// Choose better name for Serializer or even split it up
class AbcdSerializer final
{
public:
AbcdSerializer(QFile& file)
: _file(file)
{
}
// You may also throw an exception instead of returning optional
Opt<Abcd> TryDeserializeAbcd()
{
long rX;
long rY;
long count;
if (ReadValue(rY) && ReadValue(rX) && ReadValue(count))
{
return Abcd(rX, rY, count);
}
return {};
}
bool SerializeAbcd(const Abcd& abcd)
{
return WriteValue(abcd.GetRY()) && WriteValue(abcd.GetRX()) && WriteValue(abcd.GetCount());
}
private:
template <typename T>
bool ReadValue(T& value)
{
constexpr auto ValueSize = sizeof(value);
return _file.read(reinterpret_cast<char*>(&value), ValueSize) != ValueSize;
}
template <typename T>
bool WriteValue(const T& value)
{
constexpr auto ValueSize = sizeof(value);
return _file.write(reinterpret_cast<const char*>(&value), ValueSize) != ValueSize;
}
QFile& _file;
};
I am trying to create a helper class to abstract invoking function pointers. With feedback from others on SO, I am using a polymorphic class to achieve this (shown below). Templates are also used to reduce code duplication.
typedef void(*PFNFOO1) (int);
typedef void(*PFNFOO2) (double);
typedef void(*PFNBAR1) (long);
typedef void(*PFNBAR2) (float);
typedef struct FOO_TABLE
{
PFNFOO1 pfnFoo1;
PFNFOO2 pfnFoo2;
} FOO_TABLE;
typedef struct BAR_TABLE
{
PFNBAR1 pfnBar1;
PFNBAR2 pfnBar2;
} BAR_TABLE;
enum TABLE_TYPE
{
TYPE_FOO = 0,
TYPE_BAR = 1,
};
template <typename T>
class FooBarImpl : public FooBarBase
{
public:
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnFoo1() { return GetFunc(offsetof(T, pfnFoo1)); }
void* GetpfnFoo2() { return GetFunc(offsetof(T, pfnFoo2)); }
void* GetpfnBar1() { return GetFunc(offsetof(T, pfnBar1)); }
void* GetpfnBar2() { return GetFunc(offsetof(T, pfnBar2)); }
T* m_FooBarTable;
};
class FooBarBase
{
public:
static FooBarBase* CreateFooBar(TABLE_TYPE tableType)
{
switch(tableType)
{
case (TYPE_FOO) :
{
return new FooBarImpl<FOO_TABLE>();
}
break;
case (TYPE_BAR) :
{
return new FooBarImpl<BAR_TABLE>();
}
break;
}
}
virtual void* GetpfnFoo1() = 0;
virtual void* GetpfnFoo2() = 0;
virtual void* GetpfnBar1() = 0;
virtual void* GetpfnBar2() = 0;
};
int _tmain(int argc, _TCHAR* argv[])
{
{
FooBarBase *pFooBar = FooBarBase::CreateFooBar(TYPE_FOO);
// Initialize Foo table
auto p = reinterpret_cast<PFNFOO1>(pFooBar->GetpfnFoo1());
int parameter = 1;
p(parameter);
}
{
FooBarBase *pFooBar = FooBarBase::CreateFooBar(TYPE_FOO);
// Initialize Bar table
auto p = reinterpret_cast<PFNBAR2>(pFooBar->GetpfnBar2());
float parameter = 1.0f;
p(parameter);
}
return 0;
}
This is currently giving me complication errors as "C2039: 'pfnBar1' : is not a member of 'FOO_TABLE'" which makes sense because one of the implicit template specialization will try to do "offsetof(FOO_TABLE, pfnBar1)," which isn't allowed. I have two questions. First, I am wondering what's the best way to address this error. I think I can possibly address this by providing explicit template specializations for FooBarImpl and FooBarImpl, but I'd like to avoid doing that because it means that if I were to add a new table type later, I'd have to add another specialization. Also, it increases code duplication. Therefore, if there's a way to fix this issue without explicit template specialization, please let m know.
For my second question, if explicit template specialization cannot be avoided, I have also tried this:
class FooBarBase;
template <typename T>
class FooBarImpl : public FooBarBase
{
};
template <>
class FooBarImpl<FOO_TABLE> : public FooBarBase
{
public:
typedef FOO_TABLE T;
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnFoo1() { return GetFunc(offsetof(T, pfnFoo1)); }
void* GetpfnFoo2() { return GetFunc(offsetof(T, pfnFoo2)); }
T* m_FooBarTable;
};
template<>
class FooBarImpl<BAR_TABLE> : public FooBarBase
{
public:
typedef BAR_TABLE T;
// GetFunc is created to centralize needed validation before function is invoked
void* GetFunc(size_t funcOffset)
{
// do some validation
return reinterpret_cast<void*>(m_FooBarTable + funcOffset);
}
void* GetpfnBar1() { return GetFunc(offsetof(T, pfnBar1)); }
void* GetpfnBar2() { return GetFunc(offsetof(T, pfnBar2)); }
T* m_FooBarTable;
};
But for some reason, I keep getting this error "error C2504: 'FooBarBase' : base class undefined" even if it was working fine before I specialized the templates.
If anyone has ideas about these 2 questions, I'd really appreciate your feedback. Thanks.
I have class called "UltrasoundTemplate". These UltrasoundTemplate objects contain an int parameter, which shows when they where defined (something like a time stamp). And I have a class called "UltrasoundTarget" which contains a vector of UltrasoundTemplate's.
I add UltrasoundTemplates to the vector with push_back(ultrasoundTemplate).
Now I want to sort the vector by the order of time stamps instead of the order I added them to the vector.
I found a lot of answers in google, which all show me the same solution, but obviously I'm still doing something wrong. Here are the code snippets I think are necessary for finding a solution:
ultrasoundTemplate.h
class UltrasoundTemplate
{
public:
UltrasoundTemplate(/*...*/);
int getVolumePos() { return volume_; }
private:
int volume_;
};
ultrasoundTarget.h
//the sort algorithm
struct MyTemplateSort {
bool operator() ( UltrasoundTemplate t1, UltrasoundTemplate t2){
int it1 = t1.getVolumePos();
int it2 = t2.getVolumePos();
if (it1 < it2)
return true;
return false;
}
};
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
FMainWindow.cpp
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName) {
//here I try to sort
MyTemplateSort tmpltSrt;
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
break;
}
}
As an example: I define Template1 in Volume(0), Template2 in Volume(70) and Template3 in Volume(40). The order now is (Template1, Template2, Template3) but I want it to be (Template1, Template3, Template2). But this code is not doing it.
If there's Information missing, just tell me and I'll provide more code.
Thanks alot.
Your getTemplates() method returns by value, making a mess here:
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
You are sorting an incompatible iterator range. You can fix that particular problem by returning a reference:
vector<UltrasoundTemplate>& getTemplates() { return USTemplateVector_; }
It is common practice to add a const overload to such a method:
const vector<UltrasoundTemplate>& getTemplates() const { return USTemplateVector_; }
You can also modify your comparison functor to avoid unnecessary copies (and for general readability and const correctness):
struct MyTemplateSort {
bool operator() const ( const UltrasoundTemplate& t1, const UltrasoundTemplate& t2)
{
return t1.getVolumePos() < t2.getVolumePos();
}
};
This will require that you make getVolumePos() a const method, which it should be anyway:
class UltrasoundTemplate
{
public:
...
int getVolumePos() const { return volume_; }
...
};
Note that is is not generally good practice to provide references to the private data of a class. If possible, you should find a way to remove that from the UltraSoundTarget interface. You could, for instance, expose a pair of iterators, and/or give the class a sort method.
juanchopanza answer is correct, the problem is the way you are returning the vector from UltrasoundTarget. Just to touch another topic, maybe it would be nice to change a little the designing of your implementation. As UltrasoundTarget is a container of Ultrasound's, it makes sense to implement the sort as a method of this class, this way you have direct access to USTemplateVector_ and will save unecessary copies. Something like:
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
void sort();
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
void UltrasoundTarget::sort()
{
std::sort(USTemplateVector_.begin(), USTemplateVector_.end(), tmpltSrt);
}
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName)
{
//here I try to sort
MyTemplateSort tmpltSrt;
USTargetVector.at(i).sort();
break;
}
}
I'm trying to learn a little more about D's compile time evaluation and understand how its templates, mixins, attributes, etc all work. One thing I'd like to try and do is figure out an elegant way to mark a class's members as being serializable or loadable from a database. In the example below, I've created a tuple that lists which members to use when reading or (later on) serializing the instance.
My first question is, is this a proper usage of tuples as it stands below? And secondly, if so, is there a way to generate this tuple automatically at compile time using the user defined attributes I've assigned to the relevant member variables? I've dug through the various documentation pages like http://dlang.org/attribute.html and http://dlang.org/phobos/std_traits.html but I can't seem to figure out how to use them properly for this purpose (i.e. looping through a class's members and determining which variables have the desired attribute). I'm also not quite certain if I have completely the wrong idea about how attributes are supposed to be used. Any suggestions on the best way to go about this would be appreciated.
enum ENCODABLE = 1;
alias string[string] Row;
template Tuple (T...) { alias T Tuple; }
class A {
#(ENCODABLE) string name;
#(ENCODABLE) int x;
int* p;
alias Tuple!("name","x") encodables;
this(Row row) {
foreach (var; encodables) {
__traits(getMember, this, var) = to!(typeof(__traits(getMember, this, var)))(row[var]);
}
}
}
void main() {
Row row = ["name":"Asdf", "x":"120"]; // Simulated database row
auto a = new A(row);
writefln("%s,%d,%d", a.name, a.x, a.p); // Asdf,120,null
}
This isn't much of an answer, but I used them by defining my own helper templates, and using structs as UDAs (with their values indicating parameters). The helper templates are here:
https://github.com/CyberShadow/ae/blob/master/utils/meta.d#L133
They're used here, to allow overriding the JSON field for a JSON serializer/unserializer:
https://github.com/CyberShadow/ae/blob/master/utils/json.d#L505
I've managed to get it working with the following code, and a little help from the isValueInTuple template based on code provided in CyberShadow's answer. It still feels a bit clunky, but seems to get the job done. Comments/criticism welcome if I'm doing something horrible against the nature of templates!
enum {
ENCODABLE = "ENCODABLE",
};
alias string[string] Row;
template Tuple(T...) { alias T Tuple; }
template isValueInTuple(string s, T...) {
static if (T.length == 0) {
enum bool isValueInTuple = false;
} else static if (T.length == 1) {
static if (is(typeof(T[0]) == typeof(s))) {
enum bool isValueInTuple = T[0] == s;
} else {
enum bool isValueInTuple = false;
}
} else {
enum bool isValueInTuple = isValueInTuple!(s, T[0]) || isValueInTuple!(s, T[1..$]);
}
}
template GenEncodables(U) {
string GenEncodables() {
string ret = "alias Tuple!(";
int fn = 0;
foreach (index, field; __traits(allMembers, U)) {
static if (field != "Monitor") { // better way to avoid compilation errors here?
static if (isAssignable!(typeof(mixin(U.stringof~"."~field)))) {
static if (isValueInTuple!(ENCODABLE, __traits(getAttributes, mixin(U.stringof~"."~field)))) {
if (fn++)
ret ~= ",";
ret ~= `"`~field~`"`;
}
}
}
}
ret ~= ") encodables;";
return ret;
}
}
mixin template Encodables() {
mixin(GenEncodables!(typeof(this)));
}
class A {
#ENCODABLE string name;
#ENCODABLE int x;
int *p;
this() {}
mixin Encodables; // must come after this() definition, apparently!
this(Row row) {
foreach (var; encodables) {
pragma(msg, "Reading parameter "~var~" from row");
__traits(getMember, this, var) = to!(typeof(__traits(getMember, this, var)))(row[var]);
}
}
}
So, I have got the following classes and methods:
Property: Has a single member of type int (named mTag)
TypedProperty: Inherits from the Property class and adds a member called mValue of type T to it.
PropertyList: A class which Maintains a std::set of Property and has an Add and Print method.
CheckSubset: A method which checks if a std::set is included in another set.
I don't know how I should implement the CheckSubset method. Because I do not know how to iterate through a set<Property> and access to the template member (mValue). I also tried to use the includes method, which did not work (even if it worked, I would have no idea how it did!). The same problem exists in the PropertyList::Print method, where I do not know what cast should be used.
Any advice on the implementation of CheckSubset and Print methods would be appreciated!
Updated source code (using pointer)
#include <string>
#include <iostream>
#include <set>
#include <algorithm>
#include <tr1/memory>
using namespace std;
/////////////////// Property Class //////////////////////
class Property
{
public:
Property(){};
Property(const int tag)
: mTag(tag) {}
virtual ~Property() {}
int mTag;
bool operator<(const Property &property) const
{
return mTag < property.mTag;
}
};
/////////////////// TypedProperty Class /////////////////
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const int tag, const T& value)
: Property(tag), mValue(value){}
T mValue;
};
/////////////////////////////////////////////////////////
typedef std::tr1::shared_ptr<Property> PropertyPtr;
/////////////////// PropertyList Class /////////////////
class PropertyList
{
public:
PropertyList(){};
virtual ~PropertyList(){};
template <class T>
void Add(int tag, T value)
{
PropertyPtr ptr(new TypedProperty<T>(tag, value));
mProperties.insert(ptr);
}
void Print()
{
for(set<PropertyPtr>::iterator itr = mProperties.begin(); itr != mProperties.end(); itr++)
{
cout << ((PropertyPtr)*itr)->mTag << endl;
// What should I do to print mValue? I do not know its type
// what should *itr be cast to?
}
}
set<PropertyPtr> mProperties;
};
//////////////////// Check Subset ///////////////////////
/*
* Checks if subset is included in superset
*/
bool CheckSubset(set<PropertyPtr> &superset, set<PropertyPtr> &subset)
{
// How can I iterate over superset and subset values while I do not know
// the type of mValue inside each Property?
// I also tried the following method which does not seem to work correctly
return includes(superset.begin(), superset.end(),
subset.begin(), subset.end());
}
int main()
{
PropertyList properties1;
properties1.Add(1, "hello");
properties1.Add(2, 12);
properties1.Add(3, 34);
properties1.Add(4, "bye");
properties1.Print();
PropertyList properties2;
properties2.Add(1, "hello");
properties2.Add(3, 34);
if(CheckSubset(properties1.mProperties, properties2.mProperties)) // should be true
cout << "properties2 is subset!" << endl;
PropertyList properties3;
properties3.Add(1, "hello");
properties3.Add(4, 1234);
if(CheckSubset(properties1.mProperties, properties3.mProperties)) // should be false
cout << "properties3 is subset!" << endl;
}
What you want, cannot be done with the current design.
Your approach fails with std::set<Property>.
std::set<Property> will slice. That means that it will only copy the Property part and forget to copy the additional TypedProperty<T> members.
As a result, inside PropertyList::print(), there is no way to access the mValue.
If you want to store TypedProperty<T>s inside a std::set, you must use some sort of pointer. I.e. either std::set<Property*>, or a smart pointer version.
For solving the problem in Print method of PropertyList, you could write a Print method for TypedProperty class, which prints its tag and value.
But about the problem in accessing mValue which you want to do some operations on, I can't think of a way using normal types and templates to get the mValue without engaging your parent class Property with template type of TypedProperty (which seems undesirable). But you could get the address of mValue and cast it to void* to eliminate the type problem. This way you will face another problem, that you can not point to value of a void* pointer, so you can not work with your pointer in parent level. Therefore, you should write a method (implemented by TypedProperty) that takes a void* pointer and casts it to the type defined in child and perform the desired operation.
For example in the following code, I assumed you want to check equality of a value in a TypedProperty with another one of the same type (IsEqual method).
Now you can implement simply CheckSubset using IsEqual (checking two elements would be like: superItr->IsEqual(subItr->GetValue())).
class Property
{
public:
Property(){};
Property(const int tag)
: mTag(tag) {}
virtual ~Property() {}
virtual void* GetValue() = 0;
virtual bool IsEqual(void* value) = 0;
virtual void Print() = 0;
int mTag;
bool operator<(const Property &property) const
{
return mTag < property.mTag;
}
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const int tag, const T& value)
: Property(tag), mValue(value){}
void* GetValue()
{
return &mValue;
}
bool IsEqual(void* value)
{
return *((T*)value) == mValue;
}
void Print()
{
cout << "Tag: " << mTag << ", Value: " << mValue << endl;
}
T mValue;
};
typedef std::tr1::shared_ptr<Property> PropertyPtr;
class PropertyList
{
public:
PropertyList(){};
virtual ~PropertyList(){};
template <class T>
void Add(int tag, T value)
{
PropertyPtr ptr(new TypedProperty<T>(tag, value));
mProperties.insert(ptr);
}
void Print()
{
cout << "-----------" << endl;
for(set<PropertyPtr>::iterator itr = mProperties.begin(); itr != mProperties.end(); itr++)
{
(*itr)->Print();
}
}
set<PropertyPtr> mProperties;
};