views:

131

answers:

1

Hi! 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;
};
+1  A: 

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.

Logan Capaldo
ah it seems you're right.. but how do I have to define the addProperty function then? I added the definition of the IShader class in the problemdescription. the addProperty should allow to add Properties of any generic type to the m_shaderProperties map
Mat
Thx again! but the the IShader needs to be generic too, because it has a 'shade' function which needs to return a generic value (there can be instances of shaders that return float, others return Vector4 and so on). Each shader shall maintain a heterogeneous collection of properties (as you assumed correctly). Each property on the other hand can store the pointer to one Shader OF IT'S OWN GENERIC TYPE (so - shaders store arbitrary properties - a property stores a shader of it's own type). This also gives me the problem of mutual inclusion and need to use forward declaration somehow...
Mat
See my lastest for how to make IShader templated and to forward decalre it so a ShaderProperty can continue a pointer to one.
Logan Capaldo
Works like a charm! :) thank you very much!! the only problem left is that i don't see how to separate the definition from the implementation. how would be the right syntax to write the implementation of let's say getProperty() in the cpp file?
Mat
Assuming you understand the limitations (i.e. you know you can't actually do separate compilation with templates) the syntax looks like `template<typename ShaderType> template<typename T> void IShader<ShaderType>::getProperty(string, ShaderProperty<T>** out) { ... }`
Logan Capaldo