Составление членов во время компиляции - PullRequest
1 голос
/ 19 марта 2012

У меня есть куча атрибутов, которые могут быть либо NOP, либо иметь состояние. Требование к ним - не иметь никакого размера, когда пользователю не нужен атрибут, но при этом содержать определенные методы. Пример:

struct AttributeATag {};

/* The template used when AttributeATag is not specified */
template <typename T>
class AttributeA
{
public:
    void foo(uint32_t v)
    {
        // Nop, do nothing
    }

    enum
    {
        HasAttributeA = false
    };
};

/* The template specialization used when AttributeATag is specified */
template <>
class AttributeA<AttributeATag>
{
public:
    void foo(uint32_t v)
    {
        this->omgVariable = v;
    }

    enum
    {
        HasAttributeA = true
    };
protected:
    int omgVariable;
};

template <typename ATag>
class MyUberClass : public AttributeA<ATag>
{
    // This class now has omgVariable or not, depending on ATag and it
    // has either a NOP method or one which actually does something
    void doSomething()
    {
        if (AttributeA<ATag>::HasAttributeA)
        {
            /* ... */
        }
    }
};

Это работает, но теперь есть проблема: размер атрибутов NOP, хотя и является пустыми классами, не равен 0, что означает, что 100 пустых атрибутов добавляют много неиспользуемого пространства в MyUberClass.

Есть ли способ избежать этого и добавить / удалить переменные-члены на основе параметра шаблона?


EDIT:

Насколько я знаю, пустые классы не имеют размера 0. Когда я пытаюсь сделать следующее, я получаю sizeof (B) == 4.

template <typename T>
class A
{

};

class B : public A<int>, public A<double>, public A<char>, public A<long>, public A<bool>
{

};

Ответы [ 3 ]

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

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

Каждый класс (base / children) должен занимать как минимум один байт (и, возможно, четыре, если ваш компилятор дополняет все), но пустые основания (почти в каждом случае) не увеличивайте размер дочерних классов сверх того, что они уже имели бы.

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

Пустой класс будет иметь минимальный размер 1 байт, независимо от того, какое количество (пустых) классов унаследовано или нет.
В вашем примере class B будет иметь минимальный размер, определенный реализацией, (который кажется 4 байта в вашем случае), наследуете ли вы от других классов или не наследуете.

Это необходимо для того, чтобы любой пустой объект class мог иметь уникальный адрес.С этим ничего не поделаешь.

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

в этом тесте:

#include <iostream>
struct g{};
int main()
{
    std::cout << sizeof(g) << std::endl;
}

на gcc Я получаю размер 1, это, вероятно, потому, что вам все еще нужно иметь указатель на него, независимо от того, содержит ли он состояние.

Я не думаю, что вокруг это далеко, не прибегая к чему-то другому, кроме класса.

...