gpt4 book ai didi

c++ - 初始化模板化、递归、POD 结构

转载 作者:可可西里 更新时间:2023-11-01 17:57:31 24 4
gpt4 key购买 nike

我正在尝试使用模板递归来生成嵌套的 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]中的一条注释:

[ Note: As a consequence, if the initialization of an object obj1 refers to an object obj2 of namespace scope potentially requiring dynamic initialization and defined later in the same translation unit, it is unspecified whether the value of obj2 used will be the value of the fully initialized obj2 (because obj2 was statically initialized) or will be the value of obj2 merely zero-initialized. For example,

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是否使用。

一个变通方法是使用 construct on first use idiom 并做类似的事情(为了简单起见,我冒昧地从 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在两个编译器上。

关于c++ - 初始化模板化、递归、POD 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32085442/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com