I'm trying to use a generic enum type in a C++/CLI helper class and I want it to default to 0 if the cast doesn't work. My problem is that result = (T)0; doesn't work. Is there a way around this?
Error 1 error C2440: 'type cast' : cannot convert from 'int' to 'T'
generic <typename T> where T: value class, Enum
static void SetEnumPropertyValue(String^ value, [Out] T %result)
{
if (String::IsNullOrEmpty(value))
false;
if (!Enum::TryParse<T>(value, true, result))
{
result = (T)0;
}
}
Either use:
result = (T)Enum::ToObject(T::typeid, 0);
or the slightly "uglier":
result = (T)(Object^)0;
Related
I have the following templated function:
template<typename T = CRecordset>
std::unique_ptr<T> ExecuteSqlQuery(LPCTSTR pszSqlQuery = nullptr, RecordsetMode nMode = RecordsetMode::read)
{
ASSERT(m_Database.IsOpen());
std::unique_ptr<ITableRecordset> prs = std::make_unique<T>(&m_Database);
if (!ExecuteSqlQuery(prs.get(), pszSqlQuery, nMode))
prs.reset();
return prs;
}
And I'm calling it like this:
auto prs = db.ExecuteSqlQuery<CCustomerRecordset>(nullptr, RecordsetMode::bulkRead);
CCustomerRecordset derives from CTableRecordset<>, and CTableRecordset<> derives from ITableRecordset.
However, the return statement in the function gives me an error:
Error C2440 'return': cannot convert from std::unique_ptr<ITableRecordset,std::default_delete<_Ty>>' to 'std::unique_ptr<CCustomerRecordset,std::default_delete<_Ty>>'
with
[
_Ty=ITableRecordset
]
and
[
_Ty=CCustomerRecordset
]
Since CCustomerRecordset is a type of ITableRecordset, why can't I do this?
Your example reduces to this:
struct A {};
struct B : A {};
A *a = new B;
B *b = a;
The return statement is trying to return a unique_ptr<ITableRecordset> where a unique_ptr<CCustomerRecordset> is expected. It's a downcast, and won't happen implicitly. A way to fix it would be to make full use of the concrete type throughout the function template. So instead of converting to the interface:
auto prs = std::make_unique<T>(&m_Database);
I have a couple of A like classes with method, say, get_value(), which return values of different types. And one class B, which returns a value with method value(). For example:
struct A_like1 {
int get_value() const { return 10; }
};
struct A_like2 {
char get_value() const { return 'a'; }
};
struct B
{
float value() const { return 2.5; }
};
Now, I need a function to retrieve that value for these classes. I have a function:
template<typename T>
auto get_value(const T & t) -> result_of<decltype(&T::get_value)(T)>::type
{
return t.get_value();
}
It gives me a number of compilation errors on VS2010 starting with:
Error 1 error C2061: syntax error : identifier 'type' c:\_data\work\vmxi\c++\vox\vox\template_specialization.h 51
For B I have an overload, which works fine. The question is, how to make get_value() work with result_of<>()?
P.S. Hmm, I have just realized that I could've used -> decltype(T().get_value()) instead, which works fine. But why doesn't result_of<>() work? Besides, I was able to declare a variable in .cpp file:
result_of<decltype(&A_like1::get_value)(A_like1)>::type i=0;
The keyword typename can be used to declare that a dependent name, like std::result_of<T>::type, is a type. Otherwise, I believe it's assumed that std::result_of<T>::type is a data member. In C++14, several type traits have gotten a using alias that includes the typename keyword for you. These alias are always have the same name as the trait, with a _t suffix.
Try :
typename result_of<decltype(&T::get_value)(T)>::type
or, with C++14 :
result_of_t<decltype(&T::get_value)(T)>
I have error in compile time
INLINE template<typename T> T *&Animation::GetKey(int subAnim, int node, int frameInSubAnim)
{
const int keyIndex = GetKeyIndex(subAnim, node, frameInSubAnim);
return static_cast<T*>(m_Keys[keyIndex]);
}
With following error
d:\before_me\motion\pipeline\animation\AnimationData.inl(98):
error C2440: 'return' : cannot convert from 'Motion::Animation::Key *' to 'Motion::Animation::Key *&'
and how i can workaround it?
The compiler is telling you that the static_cast<T*>(...) yields a temporary (rvalue) and that cannot be bound by a non-const reference (return type is T*&). Note that even it it would bind to T*const& you don't really want that.
It is not clear what you are trying to achieve, but consider returning T* (drop the reference).
I think this captures what you want and provides a hideous workaround
void* m_keys[] = { 0, 0, 0 };
template<typename T>
T*& foo(const int index)
{
return *reinterpret_cast<T**>(&m_keys[index]);
}
int main()
{
foo<int>(0) = new int();
}
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.
I am hosting SpiderMonkey in a current project and would like to have template functions generate some of the simple property get/set methods, eg:
template <typename TClassImpl, int32 TClassImpl::*mem>
JSBool JS_DLL_CALLBACK WriteProp(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
{
if (TClassImpl* pImpl = (TClassImpl*)::JS_GetInstancePrivate(cx, obj, &TClassImpl::s_JsClass, NULL))
return ::JS_ValueToInt32(cx, *vp, &(pImpl->*mem));
return JS_FALSE;
}
Used:
::JSPropertySpec Vec2::s_JsProps[] = {
{"x", 1, JSPROP_PERMANENT, &JsWrap::ReadProp<Vec2, &Vec2::x>, &JsWrap::WriteProp<Vec2, &Vec2::x>},
{"y", 2, JSPROP_PERMANENT, &JsWrap::ReadProp<Vec2, &Vec2::y>, &JsWrap::WriteProp<Vec2, &Vec2::y>},
{0}
};
This works fine, however, if I add another member type:
template <typename TClassImpl, JSObject* TClassImpl::*mem>
JSBool JS_DLL_CALLBACK WriteProp(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
{
if (TClassImpl* pImpl = (TClassImpl*)::JS_GetInstancePrivate(cx, obj, &TClassImpl::s_JsClass, NULL))
return ::JS_ValueToObject(cx, *vp, &(pImpl->*mem));
return JS_FALSE;
}
Then Visual C++ 9 attempts to use the JSObject* wrapper for int32 members!
1>d:\projects\testing\jswnd\src\main.cpp(93) : error C2440: 'specialization' : cannot convert from 'int32 JsGlobal::Vec2::* ' to 'JSObject *JsGlobal::Vec2::* const '
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>d:\projects\testing\jswnd\src\main.cpp(93) : error C2973: 'JsWrap::ReadProp' : invalid template argument 'int32 JsGlobal::Vec2::* '
1> d:\projects\testing\jswnd\src\wrap_js.h(64) : see declaration of 'JsWrap::ReadProp'
1>d:\projects\testing\jswnd\src\main.cpp(93) : error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'JSPropertyOp'
1> None of the functions with this name in scope match the target type
Surprisingly, parening JSObject* incurs a parse error! (unexpected '('). This is probably a VC++ error (can anyone test that "template void foo() {}" compiles in GCC?). Same error with "typedef JSObject* PObject; ..., PObject TClassImpl::mem>", void, struct Undefined*, and double. Since the function usage is fully instantiated: "&ReadProp", there should be no normal function overload semantics coming into play, it is a defined function at that point and gets priority over template functions. It seems the template ordering is failing here.
Vec2 is just:
class Vec2
{
public:
int32 x, y;
Vec2(JSContext* cx, JSObject* obj, uintN argc, jsval* argv);
static ::JSClass s_JsClass;
static ::JSPropertySpec s_JsProps[];
};
JSPropertySpec is described in JSAPI link in OP, taken from header:
typedef JSBool
(* JS_DLL_CALLBACK JSPropertyOp)(JSContext *cx, JSObject *obj, jsval id,
jsval *vp);
...
struct JSPropertySpec {
const char *name;
int8 tinyid;
uint8 flags;
JSPropertyOp getter;
JSPropertyOp setter;
};
Pretty sure VC++ has "issues" here. Comeau and g++ 4.2 are both happy with the following program:
struct X
{
int i;
void* p;
};
template<int X::*P>
void foo(X* t)
{
t->*P = 0;
}
template<void* X::*P>
void foo(X* t)
{
t->*P = 0;
}
int main()
{
X x;
foo<&X::i>(&x);
foo<&X::p>(&x);
}
VC++ 2008SP1, however, is having none of it.
I haven't the time to read through my standard to find out exactly what's what... but I think VC++ is in the wrong here.
Try changing the JSObject * to another pointer type to see if that reproduces the error. Is JSObject defined at the point of use? Also, maybe JSObject* needs to be in parens.
I am certainly no template guru, but does this boil down to a subtle case of trying to differentiate overloads based purely on the return type?
Since C++ doesn't allow overloading of functions based on return type, perhaps the same thing applies to template parameters.