初始化模板化的、递归的、POD结构
Initializing templated, recursive, POD struct
我正在尝试使用模板递归来生成嵌套的POD结构,并且我遇到了一些我没有预料到的行为。下面是一个简化的测试用例:
#include <cstddef>
template<std::size_t size>
struct RecursiveStruct {
public:
template <std::size_t start, std::size_t length>
struct Builder {
static const Builder value;
static const size_t mid = start + length / 2;
static const size_t end = start + length;
Builder<start, mid - start> left;
Builder<mid, end - mid> right;
};
template <std::size_t start>
struct Builder<start, 1> {
static const Builder value;
int data;
};
static const Builder<0, size> result;
};
template<std::size_t size>
const typename RecursiveStruct<size>::template Builder<0, size>
RecursiveStruct<size>::result = Builder<0, size>::value;
template<std::size_t size>
template<std::size_t start, std::size_t length>
const typename RecursiveStruct<size>::template Builder<start, length>
RecursiveStruct<size>::Builder<start, length>::value
= { Builder<start, mid - start>::value, Builder<mid, end - mid>::value };
template<std::size_t size>
template <std::size_t start>
const typename RecursiveStruct<size>::template Builder<start, 1>
RecursiveStruct<size>::Builder<start, 1>::value = { 5 };
////////////////////////////////////////////////////////
#include <iostream>
using std::cout;
using std::endl;
using std::size_t;
int main() {
cout << RecursiveStruct<1>::result.data << endl;
cout << RecursiveStruct<2>::result.left.data << endl;
return 0;
}
我希望这段代码输出
5
5
实际上,这就是我用GCC 4.8.4和5.1编译时生成的。
但是,用Clang(3.5或3.7)或Visual Studio 2010编译会导致
5
0
是我的代码或我对它的理解在某种程度上是错误的,还是Clang和Visual Studio不知何故都有导致相同错误输出的错误?
我认为两个编译器都是符合的,因为静态变量的初始化顺序未指定。最清晰的语句来自[basic.start.init]中的注释:
[注:因此,如果对象obj1的初始化引用了名称空间作用域的对象obj2可能需要动态初始化并稍后在同一翻译单元中定义,因此未指定是否使用的obj2的值将是完全初始化的obj2的值(因为obj2是静态的)初始化),或者仅仅是零初始化的obj2的值。例如,
inline double fd() { return 1.0; } extern double d1; double d2 = d1; // unspecified: // may be statically initialized to 0.0 or // dynamically initialized to 0.0 if d1 is // dynamically initialized, or 1.0 otherwise double d1 = fd(); // may be initialized statically or dynamically to 1.0
-end note]
在我们的示例中,Builder<start, 1>::value
是静态初始化的,但其他所有内容都是动态未初始化的——因此不确定是否使用完全初始化的Builder<start, 1>::value
。
一种解决方法是在第一次使用时使用结构,并做一些类似的事情(为了简单起见,我冒昧地将Builder
从RecursiveStruct
中拉出来-无论哪种方式都表现出相同的行为):
template <std::size_t start, std::size_t length>
struct Builder
{
static const size_t mid = start + length / 2;
static const size_t end = start + length;
static const Builder value() {
static const Builder value_{
Builder<start, mid - start>::value(),
Builder<mid, end - mid>::value()
};
return value_;
}
Builder<start, mid - start> left;
Builder<mid, end - mid> right;
};
template <std::size_t start>
struct Builder<start, 1> {
static const Builder value() {
static const Builder value_{5};
return value_;
}
int data;
};
template<std::size_t size>
struct RecursiveStruct {
public:
static const Builder<0, size> result;
};
template <std::size_t size>
const Builder<0, size> RecursiveStruct<size>::result = Builder<0, size>::value();
这将在两个编译器上打印5
。
相关文章:
- 使用 std::index_sequence 初始化具有固定大小数组成员的 POD 结构容器
- 带有 char[] 字段的 POD 结构的 constexpr 构造
- 是否可以使用 std::array 作为 POD 结构的数据容器?
- 从基本类型转换为非 POD 结构
- 快速将无符号字符的向量强制转换为POD结构的向量,反之亦然
- POD 结构(相同类型的成员):成员是否位于连续的内存位置?
- 在不使用默认构造函数的情况下声明 POD 结构时,会实例化什么?
- 使用指针算术通过均匀的POD结构
- 如何在标准::映射中try_emplace POD 结构?
- 如何在派生类中初始化继承的模板POD结构
- 如果将键定义为std :: string,则存储在REDIS中的POD结构的验证将失败
- 对齐非 POD 结构的缓存
- 我应该在.h文件中还是在.cpp文件中放置POD结构
- 在非 pod 结构上使用运算符 new + 初始值设定项列表
- (POD 结构、POD 类和 POD)成员的 c++ 隐式类成员初始化
- 如果我将一个POD结构分配给另一个POD组织,是否存在内存泄漏
- 如何在不引起UB的情况下将字节序列重新解释为POD结构
- 是否存在非POD结构优先于类的有效用例
- 如何在将POD结构作为变量传递时初始化它
- 解构变量模板参数中的POD结构