error C2664 + generic classes + /Wp64 - c++

I've got the following lines of code:
p_diffuse = ShaderProperty<Vector4>(Vector4(1,1,1,1));
addProperty(&p_diffuse, "diffuse");
p_shininess = ShaderProperty<float>(10.0f);
addProperty(&p_shininess, "shininess");
the addProperty function is implemented as follows:
template <class A_Type>
void IShader<A_Type>::addProperty( ShaderProperty<A_Type>* shaderProperty,
std::string propertyName )
{
m_shaderProperties[propertyName] = shaderProperty;
}
now i get a strange compiler error on the last line of the first chunk of code. addProperty works fine in the first case, but in the second (when trying to add p_shininess) i get:
error C2664: 'IShader<A_Type>::addProperty': cannot convert parameter 1 from 'ShaderProperty<A_Type> *' to 'ShaderProperty<A_Type> *'
Huh!?
a hint of the problem could be the following: if I go to the project settings and set in the C++ general tab "check for 64-bit compatibility problems" from "no" to "yes(/Wp64)" then the error reads slightly different:
error C2664: 'IShader<A_Type>::addProperty': cannot convert parameter 1 from 'ShaderProperty<A_Type> *__w64 ' to 'ShaderProperty<A_Type> *'
what's going on?? what is __w64??
edit: class definition of IShader:
template <class A_Type> class IShader {
public:
virtual ~IShader(void) {};
virtual A_Type shade(IntersectionData* iData, Scene* scene) = 0;
protected:
ShaderProperty<A_Type>* getProperty(std::string propertyName);
void addProperty(ShaderProperty<A_Type>* shaderProperty, std::string propertyName);
private:
std::map<std::string, ShaderProperty<A_Type>*> m_shaderProperties;
};

float != Vector4. Your whole class (IShader), is templated on A_Type, not just the addProperty method. /Wp64 has nothing to do with anything. The solution to this problem will need more context, you may want to define addProperty to be a template member function instead of IShader (or in addition to) being templated.
Again this will be hard to get right without knowing exactly what you are doing, but I suspect what you want is a heterogeneous collection of properties. To do this safely you'll need to employ some runtime checking.
class ISharderProperty {
public:
virtual ~IProperty() {}
};
template<typename ShadeType>
class IShader;
template <typename T>
class ShaderProperty : public IShaderProperty {
IShader<T> *m_shader;
...
};
template<typename ShadeType>
class IShader {
ShadeType shade(...) = 0;
protected:
map<string, IShaderProperty*> m_shaderProperties;
template<typename T>
void addProperty(ShaderProperty<T>* prop, string name) {
m_shaderProperties[name] = prop;
}
template<typename T>
void getProperty(const string& name, ShaderProperty<T>** outProp) {
map<string, IShaderProperty*>::iterator i = m_shaderProperties.find(name);
*outProp = NULL;
if( i != m_shaderProperties.end() ) {
*outProp = dynamic_cast<ShaderProperty<T>*>( *i );
}
}
};
You'll have to use getProperty like
ShaderProperty<float> *x;
ashader.getProperty("floatprop", &x);
if( x ) {
...
}
Alternatively, getProperty could directly return the value, but then you'll need to mention T twice, e.g.
ShaderProperty<float> *x = ashader.getProperty<float>("floatprop");
if( x ) { ... }
You'll note I use dynamic_cast and check for NULL. If you have some other mechanism for mapping property names to property types you can use that instead and static_cast. There is some runtime overhead associated with dynamic_cast.

Related

Map of template function

I have a class like this:
class factory;
using factory_ptr = std::unique_ptr<IComponent> (factory::*)() const noexcept;
class factory {
public:
factory();
~factory() = default;
std::unique_ptr<Chipset> &create(const std::string &type);
private:
template<class T>
std::unique_ptr<T> Tcreate() const noexcept;
std::map<std::string, factory_ptr> m_fac;
};
#include "factory.inl"
My template function Tcreate is just:
template<class T>
std::unique_ptr<T> factory::Tcreate() const noexcept {
return std::make_unique<T>();
}
And the other function are just:
factory::factory() {
m_fac.emplace("4001", &factory::Tcreate<chipset4001>);
m_fac.emplace("4008", &factory::Tcreate<chipset4008>);
m_fac.emplace("4011", &factory::Tcreate<chipset4011>);
m_fac.emplace("4030", &factory::Tcreate<chipset4030>);
m_fac.emplace("4069", &factory::Tcreate<chipset4069>);
m_fac.emplace("4071", &factory::Tcreate<chipset4071>);
m_fac.emplace("4081", &factory::Tcreate<chipset4081>);
m_fac.emplace("4512", &factory::Tcreate<chipset4512>);
}
std::unique_ptr<Chipset> &factory::create(const std::string &type) {
if (m_fac.find(type) == m_fac.end()) {
throw nts::exception("can't find the chipset: " + type, "FactoryCreate");
}
return (this->*(m_fac.find(type)->second))();
}
Every chipset like chipsetXXXX are a class like:
class chipsetXXXX : Chipset {}
What I want to do here with this code is to generate an std::unique_ptr<> of a certain chipset linked with a string (cf. factory::m_fac), but when I run it a lot of error message pop on my terminal (more than what my terminal can handle). but i can't figured out what go wrong with it.
The issue is that your Tcreate function does not have the required signature. You're trying to create a map of functions which return an std::unique_ptr<IComponent>, but Tcreate() returns std::unique_ptr<T>.
I'm assuming Chipset inherits from IComponent. And as you note each T inherits from Chipset. So the conversion from e.g. std::unique_ptr<chipset4001> to std::unique_ptr<IComponent> is certainly possible, but that doesn't mean that the signature matches. E.g. a pointer to a function double do_thing () can't be assigned to a function pointer expecting an int (*) ().
So the solution is to change the return type of Tcreate to std::unique_ptr<IComponent>:
template<class T>
std::unique_ptr<IComponent> factory::Tcreate() const noexcept {
return std::make_unique<T>();
}
However, when you do that, you'll now get a compile error in create(), because that tries to return an std::unique_ptr<Chipset>. It's up to you to decide what to do there. Either return std::unique_ptr<IComponent>, or change factory_ptr to be a pointer to a function returning std::unique_ptr<Chipset> (and of course change Tcreate() accordingly).

C++ Returning Multiple Types as Reference

Ok so I'm trying to setup a template method that returns a reference of an undetermined type based on a parameter request. Everything looks fine but it keeps telling me that no overloaded method of the provided template method exists when I call it. The code looks something like this:
class IObj {
public:
int id;
}
class ObjOne : public IObj {}
class ObjTwo : public IObj {}
class ObjThree : public IObj {}
enum ObjectTypes {
O1Type,
O2Type,
O3Type
}
class ObjManager {
public:
std::vector< std::unique_ptr<ObjOne> > O1Holder;
std::vector< std::unique_ptr<ObjTwo> > O2Holder;
std::vector< std::unique_ptr<ObjThree> > O3Holder;
ObjManager() {}
template <class T>
T& GetObject(int oID, ObjectTypes oType) {
if(oType == ObjectTypes::O1Type) {
for(int i = 0; i < O1Holder.size(); i++) {
if(O1Holder[i]->id == oID) {
return *O1Holder[i];
}
}
}
else if(oType == ObjectTypes::O2Type) {
for(int i = 0; i < O2Holder.size(); i++) {
if(O2Holder[i]->id == oID) {
return *O2Holder[i];
}
}
}
else if(oType == ObjectTypes::O3Type) {
for(int i = 0; i < O3Holder.size(); i++) {
if(O3Holder[i]->id == oID) {
return *O3Holder[i];
}
}
}
}
}
int main() {
std::unique_ptr<ObjManager> oManager(new ObjManager());
ObjOne& a = oManager->GetObject(0, ObjectTypes::O1Type);
return 0;
}
Everything works fine, and I can make a method that returns a reference to the object stored in the vectors if I return their specific type, but I'm trying to reduce the redundancy of making many functions to return each different type. So I wanted to make a templated method that would return an object type based on which ever type I requested.
It's not giving me any errors it just keeps underlining the -> in the expression oManager->GetObject, and tells me there is no overloaded method for the template method call. Specifically it states "no instance of function template 'ObjManager::GetObject' matches the argument list, argument types are (int, ObjectTypes)" even though I'm passing an integer and ObjectTypes:: into the function's parameter list. I've looked all over for an answer to this but have not been able to find a similar situation to draw experience on.
EDIT: Sorry should have specified that this is a precursor to a vast list of vectors, I just put 3 of them for simplicity. That's why I'm trying to make a single function that can handle the return of different types so that I don't have to make a return function for every vector I create. And the purpose of returning a reference to the specified type is because each derived type will have unique data that is not in the base class, so I'm pulling the objects for editing.
As #tobi303 commented, you should definetly use the template Parameter T in your GetObject class. Then you would actually avoid repeating yourself as the Compiler will generate the code for you that you have repeated 3 times
template <class T>
T& GetObject(int oID) {
for(int i = 0; i < OHolder<T>.size(); i++) {
if(OHolder<T>[i]->id == oID) {
return *OHolder<T>[i];
}
}
While you would have to define a OHolder Template function, too.
It is not possible to change the return type of a function based on runtime information (such as your parameters), because they are obviously unknown to the compiler.
If you will always know at compile time which object type you are going to choose, you can use a trick:
Step 1: Turn your enum into a couple of empty structs:
struct O1Type {};
struct O2Type {};
struct O3Type {};
Step 2: Instead of using else ifs, use function overloading:
ObjOne& GetObject(int oID, O1Type) {/* TODO*/}
ObjTwo& GetObject(int oID, O2Type) {/* TODO*/}
ObjThree& GetObject(int oID, O3Type) {/* TODO*/}
You can now use
ObjOne& a = oManager->GetObject(0, O1Type());
(or, even better auto& a = oManager->GetObject(0, O1Type());)
You seem to be trying to use both run-time polymorphism AND the compile-time (template) polymorphism. It doesn't work this way. You cannot return multiple types from the SAME METHOD.
What you probably want to do is to either define a method like #yussuf described, or to fully start using run-time polymorphism - in which case you don't need three containers, and the type becomes part of the object ID.
I concur with #yussuf's approach. Just do that, it probably will solve your problem.
I would also recommend to use a hash / map instead of performing linear search, but this is a different story...
Root cause
Template argument type deduction can't be solely based on the return type of the function.
On the way to a solution
You could therefore add a dummy function argument to transfer the type information:
template <class T>
T& GetObject(int oID, ObjectTypes oType, T&x) {
...
}
and in main():
ObjOne& a = oManager->GetObject(0, ObjectTypes::O1Type, a);
Then the template type can be deduced.
But this will not solve your problem. This type deduction is at compile time, so that all the possible returns of the function should return the same type (or something that can be converted to it).
This is not the case of your code, which will lead to other compilation errors (see online failure).
The solution
The only workable solution is that you determine the common denominator to return. Make the function a non-template function returning an IObj&:
IObj& GetObject(int oID, ObjectTypes oType) {
...
}
You should then manage the return object as a polymorphic obhect as well. As the return is by reference, this is fine (i.e. no slicing occurs). The returned reference will really refer to the object returned, whatever its derived type could be. But you'd have to redesign your calling code for polymorphism:
IObj& a = oManager->GetObject(0, ObjectTypes::O1Type);
Online demo
But this is somewhat clumsy because you indicate in an enum the expected type, but then end with a reference to a parent that you can't handle so easily.
Conclusion
As you indicate in the function the expected return type, you'd better go for the solution in Yussuf's rexcellent answer, but applying the technique of the dummy argument for type deduction.
Ok so after much research, I have determined the best way to accomplish this is to create a custom container class like so:
#include <vector>
#include <memory>
class Base {
public:
int ID;
Base(int id) { ID = id; }
}
class A : public Base {
public:
int X;
A(int id) : Base(id) {}
}
class B : public Base {
public:
int Y;
B(int id) : Base(id) {}
}
template <class T>
class MyContainer {
private:
std::vector<std::unique_ptr<T>> internalContainer;
public:
MyContainer() {}
~MyContainer() {}
void CreateItem(int id) {
std::unique_ptr<T> newItem(new T(id));
internalContainer.push_back(std::move(newItem));
}
T& GetItem(int id) {
for(std::vector<std::unique_ptr<T>>::iterator it = internalContainer.begin(); it!= internalContainer.end(); ++it) {
if((*it)->ID == id) {
return **it;
}
}
}
}
int main() {
MyContainer<A> AList;
MyContainer<B> BList;
AList.CreateItem(0);
BList.CreateItem(0);
A& AOne = AList.GetItem(0);
B& BOne = BList.GetItem(0);
AOne.X = 10;
BOne.Y = 20;
std::cout << std::to_string(AOne.X) << "\n";
std::cout << std::to_string(BOne.Y) << "\n";
}
Let me know your opinions on if this is acceptable or if it can be improved! :)

How to associate object with its type

I'm trying to create a statistics system in C++ which will allow me to associate a string with a value of an arbitrary type. Currently, I have it working with an enum that keeps track of the type and a void * that points to the object, but this requires me to make individual if statements for all of the types I want to support. I'd like to have it so that I can support any arbitrary type using some kind of template. I've created some test code that sort of works, but there are issues:
class Test {
std::type_index type;
void *value;
public:
template <typename T>
Test(T val) : type(typeid(val)) {
T *val_p = new T;
*val_p = val;
value = (void *)val;
}
Test() : type(typeid(void)) {
value = nullptr;
}
~Test() {
//no idea how I could make this work
}
template <typename T>
T get() {
if (std::type_index(typeid(T)) == type) {
T *val_p = (T *)value;
return *val_p;
} else {
throw std::bad_typeid();
}
}
};
What I have so far works, but I don't think it would be possible to implement a destructor or copy/move constructors. The whole point is I want to store this all in a single std::unordered_map, so I can't (AFAIK) just make a template class and go from there. So, is it possible to do what I'm trying to do, and if so, how would I do it?
Based on the suggestion of GManNickG, I'm going with boost::any, as it most closely resembles what I'm looking for.
I haven't yet implemented it into the code, but the basic structure will be something along the lines of:
#include <typeinfo>
#include <boost/any.hpp>
class Statistic {
boost::any value;
public:
template <typename T>
Statistic(T val) : value(val) {}
Statistic() : value() {}
template <typename T>
bool checkType() {
return typeid(T) == value.type();
}
//Will cause an exception if the type doesn't match
//Caller should check type if unsure
template <typename T>
T get() {
if (checkType<T>()) {
return boost::any_cast<T>(value);
} else {
//throw some exception
throw bad_any_cast();
}
}
}
With this, I don't need to deal with destructors or copy/move functions, since the implicit ones will call the code already implemented by the boost library.
EDIT:
Thanks to milleniumbug for pointing out boost::any already stores the std::type_info

Multiple inside-of-class typedef of shared_ptr

I can currently initialize the following class MyTest
template<class T>
class MyTest {
public:
typedef std::shared_ptr<MyTest> Ptr;
MyTest( Ptr _nextTest = NULL ) : m_nextTest( _nextTest ) { }
~MyTest() { }
private:
Ptr m_nextTest;
};
like so
MyTest<int>::Ptr my( new MyTest<int>() );
What I would now also like to be capable of is having a MyTest of a different type as an argument for the constructor as in
MyTest<int>::Ptr my( new MyTest<float>() );
But this obviously brakes (*1) as my typedef of Ptr within MyTest limits it to one type only. Is there a way to achieve this without specifying the second type manually for each instance of MyTest?
Edit: (comments suggested to elaborate on the question)
My aim is to build some kind of pipeline. The pipeline will consist of several independent pieces. I want to inherently control in which way those pieces can be plugged into another. Meaning, that if a current piece has int input and float output the next piece must have float as input. I got this far but as you can see my knowledge on templates is rather limited:
template<class I, class O>
class AbstractPipelineTask {
public:
typedef std::shared_ptr<AbstractPipelineTask> Ptr;
AbstractPipelineTask( Ptr _nextTask ) : m_nextTask ( _nextTask ) { }
virtual ~AbstractPipelineTask() { }
void call( I _input ) {
m_input = _input;
m_output = executeTask( m_input );
if ( m_nextTask )
m_nextTask->call( m_output );
}
virtual O executeTask( I _input ) = 0;
protected:
Ptr m_nextTask;
I m_input;
O m_output;
};
template<class I, class O>
class ActualPipelineTask : public AbstractPipelineTask< I, O > {
public:
typedef std::shared_ptr<ActualPipelineTask> Ptr;
ActualPipelineTask( AbstractPipelineTask<I,O>::Ptr _nextTask ) : AbstractPipelineTask( _nextTask ) { }
virtual ~ActualPipelineTask() { }
virtual O executeTask( I _input ) {
return ( _input * _input );
}
};
class Str2IntPipelineTask : public AbstractPipelineTask< std::string, int > {
public:
typedef std::shared_ptr<Str2IntPipelineTask> Ptr;
Str2IntPipelineTask( AbstractPipelineTask<std::string,int>::Ptr _nextTask = NULL ) : AbstractPipelineTask( _nextTask ) { }
virtual ~Str2IntPipelineTask() { }
virtual int executeTask( std::string _input ) {
return atoi( _input.c_str() );
}
};
I can plug together as many ActualPipelineTasks as I want but I cant combine any that don't have the exact same I and O types:
// Works
ActualPipelineTask<int,int>::Ptr pipeTask2( new ActualPipelineTask<int,int>() );
ActualPipelineTask<int,int>::Ptr pipeTask1( pipeTask2 );
// Doesn't work (*2)
ActualPipelineTask<int,int>::Ptr pipeTask2( new ActualPipelineTask<int,int>() );
ActualPipelineTask<int,int>::Ptr pipeTask1( pipeTask2 );
Str2IntPipelineTask::Ptr pipeTask0( pipeTask1 );
I probably used the wrong tool for what I want to achieve. But that was the only one I could come up with.
*1:
error C2664: 'std::_Ptr_base<_Ty>::_Reset0' : cannot convert parameter 1 from 'MyTest *' to 'MyTest *'
*2
error C2664: 'std::shared_ptr<_Ty>::shared_ptr(std::nullptr_t)' : cannot convert parameter 1 from 'std::shared_ptr<_Ty>' to 'std::nullptr_t'
MyTest<int> and MyTest<float> are totally unrelated types. A pointer (smart or plain) to one of these types cannot point to an object of the other one, regardless of any typedefs involved.
If you want to be able to have a pointer capable of pointing to both, you'll have to redesign the MyTest class template - perhaps derive it from a non-template base class. But bear in mind that this would indeed be a redesign - you'd probably need a virtual interface in this base class, and so on. Approach the problem as such. There's no easy hack available.
Regarding your update.
Always bear in mind templates are a compile-time construct. You can use templates when the way you use them is known at compile time. In your situation, that's not quite the case.
You've incorporated both the input type and output type into type of the task. Therefore, when building the pipeline, each task in the pipeline must know the input type and the output type of the next task.
How you can solve this depends on how you intend to use the pipeline. There are two possible situations:
Scenario A. You know the structure (the type sequence) of the pipeline at compile time, and just want to be able to select the tasks at runtime. You can do that with your current classes simply by separating the "sequencing" functionality from the "execution" functionality (which would be a good idea anyway: a class should have just a single responsibility). The code would then look like this:
template<class I, class O>
class AbstractPipelineTask {
public:
typedef std::shared_ptr<AbstractPipelineTask> Ptr;
virtual ~AbstractPipelineTask() { }
virtual O executeTask( I _input ) = 0;
protected:
Ptr m_nextTask;
};
class MyKnownPipeline
{
AbstractPipelineTask<int, int>::Ptr task0;
AbstractPipelineTask<int, std::string>::Ptr task1;
AbstractPipelineTask<std::string, int>::Ptr task2;
public:
// Functions to set up the tasks somehow
int call(int input)
{
return task2->execute(task1->execute(task0->execute(input)));
}
};
To make this more flexible (e.g. if you have multiple pipelines), you could turn MyKnownPipeline into a variadic class template. I consider doing that beyond the scope of this answer, it would be rather complex template code.
Scenario B. You don't know the structure of the pipeline at compile time. You just know you'll have a pipeline and configure it somehow at runtime (or only with runtime information).
In that case, templates can't really help you (at least on the interface part). You need the abstract base class to be type-independent. Look into ways of doing type erasure and storing data of unknown type in memory (see e.g. Boost.Variant or Boost.Any).
You could still use templates on the implementation side. Here's an idea of what could be done; I don't guarantee it's complete, correct or wise to do it that way.
class AbstractTask
{
public:
virtual bool acceptableNext(const AbstractTask &next) const = 0;
virtual boost::any execute(boost::any input) = 0;
};
template <class I>
class KnownInputTask : public AbstractTask
{
public:
boost::any execute(boost::any input) override final
{
return execute_impl(any_cast<I>(input));
}
private:
virtual boost::any execute_impl(I) = 0;
};
template <class I, class O>
class KnownInOutTask : KnownInputTask<I>
{
public:
bool acceptableNext(const AbstractTask &next) const override
{
return dynamic_cast<KnownInputTask<I>*>(&next) != nullptr;
};
};
class Pipeline
{
std::vector<AbstactTask::Ptr> tasks;
public:
bool addTask(AbstractTask::Ptr task)
{
if (!tasks.empty() && !tasks.back()->acceptableNext(*task)) return false;
tasks.push_back(task);
return true;
}
boost::any call(boost::any input) const
{
for (auto t : tasks)
input = t->execute(input);
return input;
}
};

Setting data members with generic setter

I'm trying to implement a superclass in c++ that would implement one method:
-void setValueForKey(void *value, string key);
all this method would have to do is to set the value of a property associated with a given key to the new value.
This would be easy in a language that implements introspection mechanisms; as far as I know C++ doesn't.
In order to accomplish this I created another method:
void registerKeyForProperty(void *propertyPtr, string key);
all this method does is it stores in and internal map a pointer to a property associated with a given key, so all my subclasses would call this for every property they declare and I would have a way of setting values for properties without necessity to use the setters.(That's what I need!) (I explain why at the end of the post...)
for this second function I have the following implementation:
void registerKeyForProperty(void *propertyPtr, string key){
_keysDictionary->insert(pair<string,void*>(key,property));
}
where _keysDictionary is a stl map.
for the first one I have the following implementation:
void ConstructableObject::setValueForKey(void* value, string key) {
map<string,void *>::iterator it=_keysDictionary->find(key);
if(it==_keysDictionary->end()){return;}//just return if there is nothing for that key
void *property=it->second;
(*property)=value;
}
the problem is the last line is not legal C++ because ofcourse I cannot just deference that void*.
My questions are:
Is there any other way of implementing the desired functionality?
Is there a "legal" way of doing this the way I am doing it? (I cannot simply use a reinterpret_cast cause I don't know what to cast to...)
Why this:
I need to parse and xml file that has some information about some objects. I'll be using TinyXML and therefore I'll have the atribute names for the objects and their values. That would be how I would like to use it:
MyClass obj();//the constructor would call setValueForKey(...,...) for every property so all are now registered
for every attribute{
obj.setValueForKey(attribute.value,attribute.name);
}
//all properties should be set now
If the key exists, why not simply do
_keysDictionary[key] = value;
Or if you want to use the iterator
it->second = value;
It could be done with using of the type awareness techniques and for example The Memento Pattern is one of choices. The following code could be extended with the some macro stuff that generating the unique keys based on the attribute pointer signature:
class introspection
{
public:
template <typename Class, typename Member>
void registerKey(std::string key, Member Class::*memberPointee, Class* classPointee)
{
typedef member_setter<Class, Member> hold_member_pointer;
base_setter* setter = new hold_member_pointer(memberPointee, classPointee);
keys.insert(std::make_pair(key, setter));
}
template <typename Value>
void setValue(std::string key, Value value)
{
if ( keys.count(key) > 0 )
{
keys[key]->set(value);
}
else
{
throw std::logic_error("no such key");
}
}
private:
struct base_setter
{
virtual void set(boost::any value) = 0;
}; // struct base_setter
template <typename Class, typename Member>
struct member_setter : base_setter
{
member_setter(Member Class::*memberPointee, Class* classPointee)
: memberPointee(memberPointee)
, classPointee(classPointee) {}
void set(boost::any value) override
{
Member newValue = boost::any_cast<Member>(value);
classPointee->*memberPointee = newValue;
}
Member Class::*memberPointee;
Class* classPointee;
}; // struct member_setter
std::map<std::string, base_setter*> keys;
}; // class introspection
struct Data
{
int value;
}; // struct Data
int main()
{
introspection i;
Data d;
d.value = 100;
i.registerKey("value", &Data::value, &d);
i.setValue("value", 200); // OK
i.setValue("value", "not valid"); // bad_any_cast
}
The one thing that could be (not so easily) improved here is provide the compile-time type check for setValue, instead of runtime any_cast casting.
Make setValueForKey be a templated function instead of a function that accepts a void pointer. That way, you can know about the type information of the property long enough to create a templated setter
class BaseSetter
{
public:
virtual void set(void* inValue) = 0;
}
template <typename T>
class SpecializedSetter
{
public:
SpecializedSetter(T* inMyValue)
: mValue(inValue)
{ }
virtual void set(void* inValue)
{
*mValue = *reinterpret_cast<T*>(inValue);
}
private:
T* mValue;
}
template <typename T>
void registerKeyForProperty(T* inValue, string inKey)
{
registerSetterForProperty(new SpecificSetter<T>(inValue), inKey);
}
This, however, assumes inValue is a pointer to the same type of data as the value on the class. To make that safe, consider boost::any or defining some other type which contains the type information from the XML file and using that rather than void*