我有一个带有子类的类(Voxel
),它可能有也可能没有get和set方法的许多不同属性(材料,密度等)。现在,我想写一些代码如下:
template <typename VoxelType>
void process(VoxelType voxel)
{
if(VOXEL_HAS_MATERIAL)
{
//Do some work which involves calling get/setMaterial()
}
if(VOXEL_HAS_DENSITY)
{
//Do some work which involves calling get/setDensity()
}
}
因此,我希望实施VOXEL_HAS_MATERIAL
和VOXEL_HAS_DENSITY
部分。两个简单的选项是:
hasMaterial()
和hasDensity()
方法添加到Voxel
类,以便在派生类中重写。hasMaterial()
和hasDensity()
创建一个类型特征类,并为每个Voxel
子类专门设置此类。使用方法(2)允许为基本类型(int等)定义特征,但这在我的情况下没有用。在这里使用类型特征是否有任何进一步的优势,或者我应该采用更简单的静态方法方法?
注意:我也知道基于SFINAE的方法,我将单独考虑。
编辑1:我更改了示例代码以显示模板的使用。我正在寻找这个问题的静态解决方案而不是运行时解决方案。理想情况下,如果编译器确定无法对给定类型执行代码,则编译器将能够删除if语句中的代码。
答案 0 :(得分:4)
为什么这些方法应该是静态的?只需在Voxel类中将方法声明为virtual bool hasMaterial();
和virtual bool hasDensity();
,并在任何子类中覆盖它们。如果有子类,则在子类中返回true,否则返回false。
然后你可以这样做:
void process(Voxel* voxel)
{
if(voxel->hasMaterial())
{
//Do some work which involves calling get/setMaterial()
}
if(voxel->hasDensity())
{
//Do some work which involves calling get/setDensity()
}
}
然后,您可以使用材质和密度的getter和setter创建类似于类的接口,并让它们继承。
答案 1 :(得分:2)
类型特征很有用,因为即使您无法更改类型本身,它们也可以轻松添加到类型中。此外,使用类型特征,您可以简单地提供合理的默认值(例如,您可以将hasMaterial
和hasDensity
委托给类的相应静态成员),然后您只需要专门化特征对于不支持此默认值的类。
答案 2 :(得分:2)
静态成员不能被覆盖。你应该把它们变成虚拟的。我想如果可能粘贴一些uml图或源代码,那么你有设计问题。
答案 3 :(得分:1)
使用静态检查,而不是使用运行时。
首先,定义这个宏:
#define HAS_MEMBER_VARIABLE( NEW_STRUCT, VAR ) \
template<typename T> struct NEW_STRUCT { \
struct Fallback { int VAR; }; /* introduce member name "VAR" */ \
struct Derived : T, Fallback { }; \
\
template<typename C, C> struct ChT; \
\
template<typename C> static char (&f(ChT<int Fallback::*, &C::VAR>*))[1]; \
template<typename C> static char (&f(...))[2]; \
\
static bool const value = sizeof(f<Derived>(0)) == 2; \
};
检查成员变量是否存在于类中。
如果变量存在,则使用SFINAE执行某些操作,如下一个示例所示:
#include <iostream>
#define HAS_MEMBER_VARIABLE( NEW_STRUCT, VAR ) \
template<typename T> struct NEW_STRUCT { \
struct Fallback { int VAR; }; /* introduce member name "VAR" */ \
struct Derived : T, Fallback { }; \
\
template<typename C, C> struct ChT; \
\
template<typename C> static char (&f(ChT<int Fallback::*, &C::VAR>*))[1]; \
template<typename C> static char (&f(...))[2]; \
\
static bool const value = sizeof(f<Derived>(0)) == 2; \
};
HAS_MEMBER_VARIABLE( x_check, x )
struct A
{
int x;
};
struct B
{
float notX;
};
template< typename T, bool hasX = x_check<T>::value >
struct doX
{
static void foo( const T & t )
{
std::cout<<"type has x variable, and it's value is "<<t.x<<std::endl;
}
};
template< typename T >
struct doX< T, false >
{
static void foo( const T & )
{
std::cout<<"type has no x variable"<<std::endl;
}
};
template< typename T >
void doFoo( const T& t )
{
doX< T, x_check<T>::value >::foo( t );
};
int main()
{
A a; a.x = 6;
B b; b.notX = 3.6;
std::cout<<"Calling foo() on A : ";
doFoo( a );
std::cout<<"Calling foo() on B : ";
doFoo( b );
}