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

Fan*_*Fox 8 c++ templates sfinae

问题

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

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.
Run Code Online (Sandbox Code Playgroud)

有没有办法通过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);
    }
};
Run Code Online (Sandbox Code Playgroud)

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

joe*_*hip 9

您可以通过依赖编译器执行空基类优化来解决此问题,方法是检查从您派生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));
};
Run Code Online (Sandbox Code Playgroud)

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

static_assert(IsEmpty<Derived, Base1, Base2, Base3>::value);
Run Code Online (Sandbox Code Playgroud)

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

这是更新的演示.

这是原始演示.(不适用于多重继承)