如何检测一个类是否有成员变量?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何检测一个类是否有成员变量?相关的知识,希望对你有一定的参考价值。

问题

我想检测一个类是否有成员变量,如果有的话就失败静态断言。就像是:

struct b 
    int a;

static_assert(!has_member_variables<b>, "Class should not contain members"). // Error.

struct c 
    virtual void a() 
    void other() 

static_assert(!has_member_variables<c>, "Class should not contain members"). // Fine.

struct d : c 

static_assert(!has_member_variables<d>, "Class should not contain members"). // Fine.

struct e : b 

static_assert(!has_member_variables<e>, "Class should not contain members"). // Error.

struct f : c 
    char z;

static_assert(!has_member_variables<f>, "Class should not contain members"). // Error.

有没有办法通过SFINAE模板实现这一目标?这个类可能具有继承或甚至具有虚函数的多继承(尽管基类中没有成员)。

动机

我有一个非常简单的设置如下:

class iFuncRtn 
    virtual Status runFunc(Data &data) = 0;
;

template <TRoutine, TSpecialDataType>
class FuncRoutineDataHelper : public iFuncRtn 
    Status runFunc(Data &data) 
        static_assert(!has_member_variables<TRoutine>, "Routines shouldnt have data members!");
        // Prepare special data for routine
        TSpecialDataType sData(data);
        runFuncImpl(sData);


class SpecificRtn : 
    public FuncRoutineDataHelper<SpecificRtn, MySpecialData> 
    virtual Status runFuncImpl(MySpecialData &sData) 
        // Calculate based on input 
        sData.setValue(someCalculation);
    
;

FunctionalityRoutines基于每个滴答进行管理和运行。它们是自定义的,可以执行各种任务,例如联系其他设备等。传入的数据可以由例程操作,并保证在每个tick执行时传递,直到功能完成。基于DataHelper类传递正确类型的数据。我不想阻止未来人们错误地将数据添加到功能例程中,因为它不太可能按照预期执行。为了强迫这一点,我希望找到一种静态断言的方法。

答案

您可以通过依赖编译器执行空基类优化来解决此问题,方法是检查从T派生的类是否与具有虚函数的空类具有相同的大小:

template<typename T, typename... BaseClasses>
class IsEmpty

    // sanity check; see the updated demo below
    static_assert(IsDerivedFrom<T, BaseClasses...>::value);

    struct NonDerived : BaseClasses...  virtual ~NonDerived() = default; ;
    struct Derived : T  virtual ~Derived() = default; ;

public:
    inline static constexpr bool value = (sizeof(NonDerived) == sizeof(Derived));
;

这应该适用于单继承和多继承。但是,在使用多重继承时,必须列出所有基类,如下所示:

static_assert(IsEmpty<Derived, Base1, Base2, Base3>::value);

显然,这个解决方案排除了final类。

Here's the updated demo.

Here's the original demo.(不适用于多重继承)

另一答案

您必须以某种方式标记类。选择一种你习惯的方式,属性或某种带枚举的整数成员。制作子课程的人必须遵循您的惯例才能使其成功。

这里的所有其他答案将是这个的一些变体。

任何使用sizeof的答案都不能保证这可以在平台,编译器甚至是同一平台和编译器上的类之间工作,因为很容易在默认的类成员对齐中容纳一个新成员,其中sizeof的大小可以对于一个子类来说容易结束。


背景:

正如您的代码和问题中所述,所有这些只是简单的基本C ad C ++代码,并且在编译时完全解决。编译器会告诉您成员是否存在。在编译之后,它是一个高效,无名,机器代码的混合物,没有任何提示或帮助这种事情本身。

用于函数或数据成员的任何名称都会在编译后有效地消失,因为您知道并在那里看到它,并且无法按名称查找任何成员。每个数据成员只能通过它与类或结构顶部的数字偏移来了解。

像.Net,Java和其他系统这样的系统是为反射而设计的,它能够按名称记住类成员,在程序运行时可以在运行时找到它们。

C ++中的模板,除非像.Net这样的混合模式C ++也在编译时解决,名称也将全部消失,因此模板本身不会给你带来任何好处。

如果缺少某些类型的特殊成员,类似于你所要求的那样,Objective-C这样的语言也必然会被写入,但是在幕后它使用了大量的支持代码和运行时管理来独立跟踪,实际的地方函数本身及其代码仍然不知道,并依赖其他代码告诉他们成员是否存在或不成为null成员。


在纯C或C ++中,您只需要创建自己的系统,并且想要动态地跟踪什么是什么。您可以创建名称字符串的枚举,列表或词典。这是通常做的,你只需要为自己留下提示。无法按照定义对未来子类进行隐式可见性的方式编译类,而不使用某些形式(如果是RTTI)。

由于这个原因,将类型成员放在类上是很常见的,这可能是一个简单的枚举。我不会指望尺寸或任何可能与平台相关的东西。

以上是关于如何检测一个类是否有成员变量?的主要内容,如果未能解决你的问题,请参考以下文章

定义一个外部类Father,有成员变量name并赋一个初值。

创建一个Point类,有成员变量x,y,方法getX(),setX(),还有一个构造方 法初始化x和y。创建类主类A来测试它。

创建一个Point类,有成员变量x,y,方法getX(),setX(),还有一个构造方 法初始化x和y。创建类主类A来测试它。

Servlet和Struts2的线程安全问题

错误回复:私有成员的继承?

一元仿函数可以有成员变量吗?