在以下库代码中:
#include <cmath>
namespace blah {
const double pi=4.0*std::atan(1.0);
}
template <int I>
class ClassB
{
public:
ClassB() {myval = blah::pi;}
private:
double myval;
};
template <int I>
class ClassA
{
public:
static ClassB<I> b;
};
template<int I>
ClassB<I> ClassA<I>::b = ClassB<I>();
template class ClassA<3>;
是在pi
的构造函数使用它之前要由其分配给其值4.0*std::atan(1.0)
的标准保证的变量ClassB
吗?
据我所知,标准pi
和static ClassA<I>::ClassB<I> b
应该按照在这个单一翻译单元中定义的顺序进行初始化 - 因此pi
应该是首先初始化。
但是,在我的实际代码库中使用上面的代码结构,我发现在Clang 3.6编译的代码中,pi
在执行ClassB
构造函数时等于零,并且仅在此之后初始化为其适当的值。
(正如我期待的那样,GCC 4.8.3首先初始化pi
。)
答案 0 :(得分:3)
简单的答案是否定的。没有保证。如果ClassB<I> ClassA<I>::b = ClassB<I>()
不是模板,那么就会有保证,因为两者都在同一个翻译单元中,但如果静态是模板类的成员,则保证不再存在(可能是因为实际的实例化可能在任何翻译单位)。
然而,在这种特殊情况下:为什么获得常数pi
的复杂方式。只是:
double const pi = 3.1415926535897932384626433832795;
应该足够了。 (如果您对任何目标计算机有任何疑问,请添加更多数字。但这比获得IEEE最准确的表示所需要的多。)因为这是静态初始化,所以保证在任何动态初始化发生之前发生。
答案 1 :(得分:0)
正如James Kanze所说,答案是否定的,订单无法保证(即使ClassA<3>
在翻译单元中明确实例化)。 This answer提供了有关此问题的更多详细信息。
一种解决方案是使用
专门化库.cpp文件中的静态成员变量template<>
ClassB<3> ClassA<3>::b = ClassB<3>();
而不是使用template class ClassA<3>;
实例化模板。
C ++ 03规范。并没有明确说明这一点,但是C ++ 11规范。在这个问题上更清楚:
明确专门化的定义 类模板静态数据成员已经订购了初始化。 其他类模板静态数据成员(即隐式地) 或明确实例化的特化)已无序 初始化。