Given:
struct Field
{
template<class T> T Value() const
{
// ???
}
template<class S> S SimpleValue() const
{
return *reinterpret_cast<const S *>(GetVoidPointerToTheActualValue());
}
template<class P> const P *PointerValue() const
{
return reinterpret_cast<const P *>(GetVoidPointerToTheActualValue());
}
};
How do I implement the Field::Value<T>() method, so that the compiler automatically dispatches to:
Field::PointerValue<P>ifTis actuallyP*Field::SimpleValue<S>otherwise
In addition it is guaranteed, that T is neither a reference nor a pointer-to-pointer type.
Thanks.
EDIT
@Grizzly – I have tried your suggestion, unfortunately it fails during the compilation of Value<LPCWSTR>():
1> playmssqlce.cpp
1>c:\dev\internal\playmssqlce\playmssqlce.cpp(75): error C2668: 'sqlserver::Field::Value' : ambiguous call to overloaded function
1> c:\dev\internal\playmssqlce\sqlserverfield.h(19): could be 'std::tr1::enable_if<_Test,_Type> sqlserver::Field::Value<LPCWSTR>(void) const'
1> with
1> [
1> _Test=false,
1> _Type=LPCWSTR
1> ]
1> c:\dev\internal\playmssqlce\sqlserverfield.h(18): or 'std::tr1::enable_if<_Test,_Type> sqlserver::Field::Value<LPCWSTR>(void) const'
1> with
1> [
1> _Test=true,
1> _Type=LPCWSTR
1> ]
1> while trying to match the argument list '(void)'
It is unclear to me why, because your advice feels right. BTW, I am using Visual Studio 2010.
EDIT2
After fixing the stupid mistake, I still have problems. So, here is what I have:
struct Field
{
template<class T> typename enable_if<is_pointer<T>::value, T>::type Value() const { return PointerValue(); }
template<class T> typename enable_if<!is_pointer<T>::value, T>::type Value() const { return SimpleValue(); }
template<class T> T SimpleValue() const { return *reinterpret_cast<const T *>(GetVoidPointerToTheActualValue()); }
template<class T> const T *PointerValue() const { return reinterpret_cast<const T *>(GetVoidPointerToTheActualValue()); }
};
I am trying to compile f.Value<const wchar_t *>(), but getting this:
1> playmssqlce.cpp
1>c:\dev\internal\playmssqlce\sqlserverfield.h(18): error C2783: 'const T *sqlserver::Field::PointerValue(void) const' : could not deduce template argument for 'T'
1> c:\dev\internal\playmssqlce\sqlserverfield.h(42) : see declaration of 'sqlserver::Field::PointerValue'
1> c:\dev\internal\playmssqlce\playmssqlce.cpp(75) : see reference to function template instantiation 'const wchar_t *sqlserver::Field::Value<const wchar_t*>(void) const' being compiled
What am I doing wrong now?
Thanks.
EDIT3
Stupid me. Noticed the change by Grizzly:
template<class T> typename enable_if<is_pointer<T>::value, T>::type Value() const { return PointerValue<typename std::remove_pointer<T>::type>(); }
template<class T> typename enable_if<!is_pointer<T>::value, T>::type Value() const { return SimpleValue<T>(); }
Works now.
You can use
enable_if:Of course
std::enable_if,std::is_pointer<T>andstd::remove_pointer<T>are only availible if you haveC++11. If you don’t you can use eitherstd::tr1::is_pointerorboost::is_pointertogether with eitherboost::enable_if(orboost::enable_if_c) or a self writtenenable_if(look here for how to do it, it’s pretty trivial).remove_pointeris also availible as bothstd::tr1::remove_pointerandboost::remove_pointer.However depending on what you want it might still not do what you want, since the way I wrote it you need to pass
const P*toValue(), since that is whatPointerValue()returns. If you want to passP*and getconst P*back, you can change it to following:Once again use
std::tr1::add_constorboost::add_constif you don’t have c++11