4

我有一个仅由静态属性组成的类,充当一种穷人的单身人士。其目的是从应用程序的各个点收集统计信息。对于我们的单元测试,我创建了一个卷影副本,可用于获取生产代码之间的差异。

例子:

struct Production {
    static ComplexClass value1;
    static ComplexClass value2;
};

struct ProductionShadow {
    static ComplexClass::ValueType value1;
    static ComplexClass::ValueType value2;
};

由于所有成员都是静态的,影子类不能从生产类继承,并且生产类中的属性是具有副作用的复杂对象,我只希望影子保存简单的值以进行比较。

为了使影子类更易于维护,我想添加一个静态断言来检查每当有人向生产类添加属性时,影子类也会更新。

如果属性不是静态的,这可以通过执行以下操作轻松完成:

enum { NumberOfProductionAttributes = sizeof(Production) / sizeof(ComplexClass),
       NumberOfShadowAttributes = sizeof(ProductionShadow) / sizeof(ComplexClass::ValueType) };
STATIC_ASSERT(NumberOfProductionAttributes == NumberOfShadowAttributes);

除了使类成为非静态类(我不想这样做,因为我必须将生产类变成一个适当的单例)之外,有没有什么办法可以用当前的实现来完成这个检查?

在运行时,我有一个方法可以使用生产类验证阴影中的所有值。由于添加新属性时也必须更新该方法,因此我希望能够计算已验证的属性数量,并在数量与属性总数不同时断言。

例子

bool ProductionShadow::verify() {
    std::size_t numberOfVerified = 0;
    #define VERIFY(x) do { \
        ++numberOfVerified; \
        // Verification code goes here \
    } while (0)
    VERIFY(value1);
    VERIFY(value2);
    ASSERT(numberOfVerified == NumberOfShadowAttributes);
    // Return result
}

如果有一个 GCC 扩展,我可以使用这可能是一个可接受的解决方案,即使我更喜欢可移植的东西。

4

3 回答 3

1

您可以使用 和 的inheritance组合template

enum ClassType { DEFAULT, SHADOW };

template<ClassType E>
struct Production_T
{
  static ComplexClass value1;
  static ComplexClass value2;
};
typedef Production_T<DEFAULT> Production;

struct ProductionShadow : Production_T<SHADOW> {
  // add only new 'static' members, others are copied from 'Production_T'
};

If some member is added to Production_T, the ProductionShadow will automatically updated. So you don't have to worry about duplicating the members in ProductionShadow.

于 2012-04-19T08:21:17.050 回答
1

Just in case, here is the solution I suggested in the comments to the question. The idea is to create two classes that contain the data members in question in the form of non-static members:

struct ProductionStaticMembers
{
  ComplexClass value1;
  ComplexClass value2;
};

struct ProductionShadowStaticMembers
{
  ComplexClass::ValueType value1;
  ComplexClass::ValueType value2;
};

And then redefine the original classes to contain the classes defined above as static members. They would continue to function as before, and size checks could be performed against the types defined above.

struct Production {
  static ProductionStaticMembers static_members;
};

struct ProductionShadow {
  static ProductionShadowStaticMembers static_members;
};

Admittedly, this means a change in how the static members are accessed (because they are now members of another member); therefore many changes to existing code might be required.

于 2012-04-19T08:29:17.110 回答
0

You could do this with macros. Its a little bit ugly but would work:

productiondecl.h

struct PRODUCTION_TYPE
{
    PRODUCTION_VAR(ComplexClass, value1);
    PRODUCTION_VAR(ComplexClass, value2);
};

production.h

#define PRODUCTION_TYPE Production
#define PRODUCTION_VAR(type,name) static type name;
#include "productiondecl.h"
#undef PRODUCTION_TYPE 
#undef PRODUCTION_VAR

productionshadow.h

#define PRODUCTION_TYPE ProductionShadow
#define PRODUCTION_VAR(type,name) static type::ValueType name;
#include "productiondecl.h"
#undef PRODUCTION_TYPE 
#undef PRODUCTION_VAR

If you cant use type::ValueType in every case, write a metafunction to elucdiate the type:

template <typename T>
struct ShadowType
{
    // default type is type::ValueType
    typedef T::ValueType type;
};
template <> ShadowType<SomeOtherType>
{
    typedef SomeOtherTypeShadow type;
}
#define PRODUCTION_VAR(type, name) static ShadowType<type>::type name;

OR, you could avoid macros and use a template policy:

struct ComplexClass {
    typedef int ValueType;
};

template <typename T>
struct ShadowType
{
    typedef typename T::ValueType type;
};
template <typename T>
struct ProductionType
{
    typedef T type;
};

template <template <typename T> class Policy>
struct ProductionBase
{
    static typename Policy<ComplexClass>::type value1;
    static typename Policy<ComplexClass>::type value2;
};

struct Production : public ProductionBase<ProductionType>
{
};
struct ProductionShadow : public ProductionBase<ShadowType>
{
};

Or, a hideous hack, using macros to avoid changing the production code:

#define Production ProductionShadow
#define ComplexClass ComplexClass::ValueType
#include "production.h"
#undef Production 
#undef ComplexClass
于 2012-04-19T08:27:27.103 回答