类型特征与静态成员的优点?

时间:2011-12-22 09:27:18

标签: c++ typetraits

我有一个带有子类的类(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_MATERIALVOXEL_HAS_DENSITY部分。两个简单的选项是:

  1. 将静态hasMaterial()hasDensity()方法添加到Voxel类,以便在派生类中重写。
  2. 使用hasMaterial()hasDensity()创建一个类型特征类,并为每个Voxel子类专门设置此类。
  3. 使用方法(2)允许为基本类型(int等)定义特征,但这在我的情况下没有用。在这里使用类型特征是否有任何进一步的优势,或者我应该采用更简单的静态方法方法?

    注意:我也知道基于SFINAE的方法,我将单独考虑。

    编辑1:我更改了示例代码以显示模板的使用。我正在寻找这个问题的静态解决方案而不是运行时解决方案。理想情况下,如果编译器确定无法对给定类型执行代码,则编译器将能够删除if语句中的代码。

4 个答案:

答案 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)

类型特征很有用,因为即使您无法更改类型本身,它们也可以轻松添加到类型中。此外,使用类型特征,您可以简单地提供合理的默认值(例如,您可以将hasMaterialhasDensity委托给类的相应静态成员),然后您只需要专门化特征对于不支持此默认值的类。

答案 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 );
}