【问题标题】:Composing members at compile-time在编译时组成成员
【发布时间】:2012-03-19 03:22:33
【问题描述】:

我有一堆属性,可以是 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 添加了大量未使用的空间。

有没有办法避免这种情况并根据模板参数添加/删除成员变量?


编辑:

据我所知,空类的大小不为 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>
{

};

【问题讨论】:

  • AttributeA&lt;ATag&gt; 只有在 ATag = AttributeTag 时才会有大小。其余案例将仅为空类。这个100 号码也是从哪里来的?我看不出有什么问题。请把你的问题说清楚。
  • 100只是为了夸大问题。

标签: c++ templates metaprogramming


【解决方案1】:

由于您使用AttributeA 作为基类,几乎每个编译器都会使用“空基优化”来确保空基类在子类中不使用任何空间,即使基类非零。我不相信你在这里有问题。

每个类(基类/子类)必须占用至少一个字节(如果您的编译器填充了所有内容,则可能占用四个字节),但空基类(几乎在所有情况下)不会使子类的大小超出它们的大小已经。

【讨论】:

  • 我刚刚使用 MSVC 10 运行了我的 EDIT(请参阅我的帖子),并且 sizeof(B) 在发布编译时仍然返回 4。你确定这是优化出来的吗?
  • 我认为这是我的编译器的问题。它应该应用空基类优化,但出于某种原因,MSVC10 仅对第一个基类执行此操作,并为其他基类添加 1 个字节。
【解决方案2】:

在这个测试中:

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

在 gcc 上我得到的大小为 1,这可能是因为无论它是否保持状态,您仍然需要能够拥有指向它的指针。

如果不求助于类以外的东西,我不会认为它周围有很远的地方。

【讨论】:

  • 课程以外的东西?那会是什么?
  • @HowieHowitzer 我的答案在哪里结束,我很害怕。也许是一个不同的设计,但这并不是那么有帮助,我很抱歉。
【解决方案3】:

无论是否继承了任何数量的(空)类,一个空类的最小大小为 1 个字节。
在您的示例中,class B 将具有最小实现定义的大小(在您的情况下似乎 4 个字节),无论您是从其他类继承还是不继承。

这是必需的,这样任何空的class 对象都可以有一个唯一的地址。对此无能为力。

【讨论】:

  • 这不是 sizeof(A) == 1 的情况。这意味着,使用我的编译器 (MSVC10),空类的大小为 1 字节,因此使用 sizeof(B) == 4 很明显,空类确实增加了 B 的大小。
猜你喜欢
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 2022-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多