//in some .h file #define BARS_IN_FOO 5 //The only place where this number should be specified. //All code should work when I change this //in some .cpp file struct Foo; struct Bar { Foo & foo; Bar(Foo & foo) : foo{ foo } {} } //Cannot be default initialized struct Foo { std::array<Bar,BARS_IN_FOO> myBars; Foo() : myBars{ } //Error. Cannot default initialize Bars. //I want to initialize all Bars with Bar{*this} but at this point I don't //know how many Bar initializers I should put in the myBar initializer list {} }
那么我应该如何初始化Foo :: myBars? Bars的数量在编译时是已知的,但我只想在一个地方指定这个数字(在定义中最好,其他建议是受欢迎的).
Foo :: mybars的用法:
>它的大小在运行期间永远不会改变,但我还没有确定它的数量是多少,但是会在[1..10](或者这样)的范围内(数字在开发过程中可能会发生很大的变化).
>元素值永远不会改变
(总是会是相同的非const对象).
> Foo和Bar之间的关系是组合. Foo由Bars制成,它们的寿命是相同的.没有Foo的酒吧和反之亦然没有道理.
> Foo和Bar类是性能关键代码的一部分,它们的大小将影响程序的内存占用(80-90%的内存占用将是Foos和Bars).
编译器:MSVS2017版本15.3
编辑:更改std :: array< Bar,BARS_IN_FOO> myBars;禁止myBars [BARS_IN_FOO];如果这有帮助,也是oke.
重要编辑:Bar和Foo的所有人都是公开的.这是一个错误.我换了这个.
解决方法
template <std::size_t ... Is> std::array<Bar,sizeof...(Is)> make_bar_array_impl(Foo& f,std::index_sequence<Is...>) { return { (Is,f)... }; } template <std::size_t N> std::array<Bar,N> make_bar_array(Foo& f) { return make_bar_array_impl(f,std::make_index_sequence<N>{}); } Foo() : myBars(make_bar_array<BARS_IN_FOO>(*this)) {}
这可以很容易地重构为使用“重复”的更通用的模板元编程实用程序.我怀疑任何模板元编程库都会有一些这样的实用程序,在这里我不打算将其分解,因为无论如何它都是一个单行程.但是如果遇到这些问题,通常需要考虑(只需编写一个返回N-entry初始化列表的函数,所有函数都使用相同的表达式).
实例:http://coliru.stacked-crooked.com/a/aab004c0090cc144.抱歉无法轻松访问MSVC编译器.还编译了14,因为我不需要任何17个功能.
编辑:即使Bar不可移动/可复制,或者如果您认为事情不会得到优化,这种技术实际上也可以修改为即使在这种情况下也能工作.您可以生成一个数组< std :: reference_wrapper< Foo>,N.但这有点复杂,通常在C中,大多数事情应该是可移动的,并且通常构造函数调用不在关键路径中.如有必要,我还可以详细说明.
Edit2:另外,请不要使用#define. constexpr static auto BARS_IN_FOO = 5;应该以完全相同的方式工作,除了它是正确的命名空间(可能还有一些我忘记的宏观肮脏).