如何在 C++03 中从初始化列表中初始化数组成员?

How to initialize array members from initialization list in C++03?

提问人:nowox 提问时间:4/15/2023 最后编辑:nowox 更新时间:4/16/2023 访问量:125

问:

以下内容在 C++11 中工作正常,但在 C++03 中不起作用。

struct Foo {
    int a, b;
    Foo(int a, int b) : a(a), b(b) {}
};

struct Bar {
    Foo foos[2];
    Bar(int i) :
        foos{ {i + 1, i + 2}, {i + 2, i + 3} },
    {}
};

int main() {}

C++03 解决方法是什么?

这个问题非常相似,但它并没有真正解决相同的用例。在这里,我想从参数构建子类。Bar

C++ 初始值设定项列表 C++03

评论

0赞 nowox 4/15/2023
提到的问题并没有真正回答这个问题。它不提供任何 C03++ 示例。
0赞 Nelfeal 4/15/2023
@Jason 我几乎可以肯定您链接的问题没有提供何时没有默认构造函数的解决方法(它是关于数组的)。它只是说它不是有效的语法。Fooint
0赞 user12002570 4/15/2023
@Nelfeal 这就是我的意思,在 c++03 中不可能按照 op 想要的“初始化”。不过,您可以在 c++03 中执行“赋值”。
0赞 Nelfeal 4/15/2023
@Jason 但是 OP 特别要求解决方法......在这里执行分配不是解决方法,因为您仍然无法 default-initialize 。foos

答:

1赞 Nelfeal 4/16/2023 #1

由于没有默认构造函数,因此如果没有 C++11 的列表初始化,则无法初始化数组。FooFoo

你的第一个选择是使用一个不到二十年的C++版本,但我想这不是你的选择,否则你不会问这个。

还有其他一些选项,但据我所知,它们都不允许您保持数组完好无损。

使用动态分配

struct BarNew {
    Foo* foos;
    BarNew(int i) : foos(static_cast<Foo*>(::operator new(sizeof(Foo) * 2)))
    {
        new (foos + 0) Foo(i+1, i+2);
        new (foos + 1) Foo(i+2, i+3);
    }
};

这可能看起来很复杂,因为如果不调用构造函数就无法直接使用,而对于数组来说这是不可能的(同样,仅在 C++11 之前)。调用分配而不初始化,就像在 C 中一样。然后,您需要使用 placement-new 来实际构造每个对象。new::operator newmalloc

std::vector

struct BarVector {
    std::vector<Foo> foos;
    BarVector(int i)
    {
        foos.reserve(2);
        foos.push_back(Foo(i+1, i+2));
        foos.push_back(Foo(i+2, i+3));
    }
};

这是最简单的选项,主要缺点是与数组不同,它也使用动态分配。调用 当然是可选的。reserve

使用数组包装器

template<class T, std::size_t N>
struct ArrayWrapper {
    union {
        char buffer[sizeof(T)];
        unsigned long long dummy;
    } storage[N];

    T& operator[](std::size_t i) {
        return reinterpret_cast<T&>(storage[i]);
    }
};

struct BarStruct {
private:
    static ArrayWrapper<Foo, 2> foos_init(int i) {
        ArrayWrapper<Foo, 2> foos;
        foos[0] = Foo(i+1, i+2);
        foos[1] = Foo(i+2, i+3);
        return foos;
    }

public:
    ArrayWrapper<Foo, 2> foos;
    BarStruct(int i) : foos(foos_init(i))
    {
    }
};

这是这三个选项中最复杂的,但它的优点是不使用动态分配。可以使它的行为与一个简单的数组非常相似。
此处的结构是泛型的,因此您可以将其用于 以外的类型。它包含一个缓冲区(数组 )来包含每个对象,并使用联合进行对齐,因为 alignas 再次是 C++11 的添加。我不是 100% 确信它在任何情况下都有效;我认为你必须祈祷有足够好的一致性。如果 ,您将浪费一些空间,但如果这让您担心,您可以编写模板专用化。
仅用于提供初始化值。在构造函数之后,您可以像数组一样使用。
ArrayWrapperFoocharFoounsigned long longsizeof(T) < sizeof(unsigned long long)foos_initfoos

看到所有三个选项都在 C++03 中编译。

我能想到的还有另一种选择,但我没有足够的信心相信它会起作用,或者我的能力来写它,所以我把它作为一个想法。它是选项 2 和 3 的组合,您可以在堆栈上提供存储,就像 一样,但随后使用它来感谢“分配器”功能(第二个模板参数)。这样一来,你就可以在不分配任何内容的情况下获得所有花哨的方法。ArrayWrapper::storagestd::vectorstd::vectorstd::vector