Проблемы с проверкой того, что мой суперкласс или базовый класс - это то, что утверждает макрос или шаблон - PullRequest
1 голос
/ 30 марта 2012

Я недавно столкнулся с неприятной проблемой. У меня есть много кода отражения, который я хотел бы скрыть в макросах. Эти макросы COMPONENT_x() используются так:

class ComponentBase : public IComponent
{
    COMPONENT(ComponentBase)
};

class ComponentDerived1 : public ComponentBase
{
    COMPONENT_DERIVED(ComponentDerived1, ComponentBase)
};

Вышеуказанное является полностью действительным. Тем не менее, я хотел бы, чтобы в этом случае произошла ошибка компиляции:

class ComponentDerived2 : public ComponentDerived1
{
    COMPONENT_DERIVED(ComponentDerived2, ComponentBase)
    //                                   ^^^^^^^^^^^^^
    // This type claims to have a superclass of ComponentBase in the above macro,
    // but we really derive from ComponentDerived1.
    //
    // I want this to result in a compile error. 
};

То есть, когда я утверждаю, что мой суперкласс (или мой базовый класс) равен ComponentBase, когда мой суперкласс на самом деле ComponentDerived1, я бы идеально хотел ошибку во время компиляции.

Причина, по которой я не могу легко обнаружить этот случай, состоит в том, что, хотя мой суперкласс ComponentDerived1, этот класс 'super' ComponentBase - и, следовательно, это также один из моих базовых классов. (Я понимаю, что ComponentDerived1 is-a ComponentBase, поэтому, возможно, есть более подходящая фраза, чем «базовый класс».)

Были некоторые комментарии, спрашивающие, почему я хочу это сделать. Я использую оптимизированную систему генерации компонентов, которая помещает все объекты одного и того же типа в отдельные буферы, поэтому важно знать знания о связях классов, если я хочу иметь такой API, как getComponentsThatImplement(ComponentDerived1::getType());.

Я взломал вместе одно решение , которое работает с g ++:

class ComponentBase : public IComponent
{
    COMPONENT(ComponentBase)

protected:
    static void helperComponentBase(); // COMPONENT(ComponentBase)
};

class ComponentDerived1 : public ComponentBase
{
    COMPONENT_DERIVED(ComponentDerived1, ComponentBase)

private:
    using ComponentBase::helperComponentBase; // COMPONENT_DERIVED(..., ComponentBase)
};

class ComponentDerived2 : public ComponentDerived1
{
    COMPONENT_DERIVED(ComponentDerived2, ComponentBase)

private:
    using ComponentBase::helperComponentBase; // error: this function is already hidden
}

К сожалению, clang с Xcode 4.3.2, похоже, не поддерживает using таким образом. Я проверил библиотеку признаков типа boost и не вижу ничего полезного. Я использую C ++ 11, поэтому я могу использовать современные конструкции.

Какие-нибудь другие умные идеи?

Ответы [ 4 ]

1 голос
/ 31 марта 2012

Вы можете использовать тот факт, что от c'tor вы не можете напрямую вызвать c'or супер'а вашего супер:

0 голосов
/ 30 марта 2012

Вы можете определенно использовать type_traits для этого. Добавьте в него время компиляции, и вы получите его. Вот код, который должен работать:

#define PARENTCHECKER_THING(__TYPE,__BASE)                     \
inline void WastedFunc()                                       \
    { COMPILE_ASSERT( (std::is_base_of<__BASE,__TYPE>().value == true) ); }


#define COMPONENT(__TYPE)                                               \
    bool __TYPE##SomeFunc(bool val) { return val; }                     \
    bool __TYPE##SomeOtherThing(bool val) { return val; }

#define COMPONENT_DERIVED(__TYPE,__BASE)                                \       
    bool __TYPE##SomeFunc( bool val) { return val; }                    \
    bool __TYPE##SomeOtherThing(bool val) { return val; }               \
    PARENTCHECKER_THING(__TYPE,__BASE);

class Base
{
    COMPONENT(Base);
    int baseData;
};

class NOT_Base
{
    COMPONENT(NOT_Base);
    int garbage;
};

class Child : public Base
{
protected:
    COMPONENT_DERIVED(Child,NOT_Base);

    float childData;
};

По общему признанию, базовому контролеру нужен только некоторый базовый класс, а не немедленный базовый. Я полагаю, что я мог бы быть немного более умным в том, чтобы не добавлять туда фиктивную функцию. Это должно быть мертвым раздетым все же.

Надеюсь, это поможет!

РЕДАКТИРОВАТЬ: Хммм ... Я пропустил пересылку в середине, где вы назвали это проблемой. Как насчет этого тогда:

#define PARENTCHECKER_THING(__TYPE,__BASE)                     \
inline void WastedFunc()                                       \
    { COMPILE_ASSERT( (std::is_same< std::common_type<__BASE,__TYPE>()::type, __BASE >().value == true) ); }

По сути, "Утверждать, если общий тип базы и дочернего элемента является чем-то отличным от базы". К сожалению, у меня нет удобной копии VS2010, и VS2008 не поддерживает common_type <>.

0 голосов
/ 30 марта 2012

Это довольно простой способ сделать это, может быть, я что-то упустил, но не могли бы вы просто заглушить фиктивную функцию (которую вы никогда не будете использовать), которая вызывает ошибку компилятора с простым присваиванием указателя:

#define COMPONENT_DERIVED(__TYPE,__BASE) \
    // your code here                    \
    void ensureBase()                    \
    {                                    \
         // compiler error:              \
         __BASE* foo = this;             \
         // to ensure __TYPE as well:    \
         __TYPE* bar = this;             \
         // to prevent compiler warning: \
         foo = bar;                      \
    }
0 голосов
/ 30 марта 2012

Я не знаю, слишком ли это хак на ваш вкус, но это может сработать. Протестировано в 2010 году. Вам нужно будет сложить статические функции в макросы отражения.

Это создает ошибку на ComponentDerrived2: ComponentDerived1::__ComponentBase : cannot access private member declared in class ComponentDerived1

class IComponent {
};

class ComponentBase : public IComponent
{
    //COMPONENT(ComponentBase)
protected:
    static void __ComponentBase() { };
};

class ComponentDerived1 : public ComponentBase
{
    //COMPONENT_DERIVED(ComponentDerived1, ComponentBase)
protected:
    static void __ComponentDerived1() { __super::__ComponentBase(); };
private:
    static void __ComponentBase() { };
public:

};

class ComponentDerived2 : public ComponentDerived1
{
    //COMPONENT_DERIVED(ComponentDerived2, ComponentBase)
protected:
    static void __ComponentDerived2() { __super::__ComponentBase(); }
private:
    static void __ComponentBase() { };
public:

};
...