模板的typedef是否保留静态初始化顺序?

时间:2009-07-10 15:54:28

标签: c++ templates static initialization typedef

在同一个编译单元中,C ++标准说明了静态初始化顺序 - 它是静态对象声明的顺序。但是使用Sun Studio 12编译器我遇到了不直观的行为。我定义了一个模板化的类helper<T>,它包含类型为_data的静态成员T和一个使用_data foo的静态成员函数。在我的.cpp文件中,我有以上main():

struct A { /* some definition */ };

typedef helper<int> s0;
typedef helper<A> s1;

请注意,helper<int>的typedef来自 helper<A>的typedef之前的。因此,根据标准,我希望在helper<int>::_data之前构建helper<A>::_data(记住_data是静态成员)。在海湾合作委员会就是这种情况,在Sun上它不是。

这是有问题的,因为A的构造函数使用helper<int>::_data。我只有一个编译单元,没有早期潜在的helper<A>实例化,所以我认为顺序应该很好定义。这是一个Sun编译器错误,还是typedef技术上不构成定义/实例化?我的意思是,标准允许Sun编译器的行为吗?

我有以下main():

int main()
{
    //Swapping the order of these has no effect on Sun
    s0::foo();
    s1::foo();
}

s0或s1没有其他用途。

2 个答案:

答案 0 :(得分:6)

  

在同一个编译单元中,C ++标准说明了静态初始化顺序 - 它是静态对象声明的顺序。

在您显示的代码中,您没有声明静态数据成员。您有一个typedef-name的声明。这些与此无关,也不影响任何订单。 你可能会想到

  

如果我发出了typedef声明,它将实例化helper<int>,从而首先实例化其静态数据成员声明。

问题是,该行不会导致helper<int>的实例化。为此,您需要一个显式实例化或管理以使其隐式实例化(例如,创建一个helper<int>对象,或者将其用作helper<int>::...中的嵌套名称说明符并显式引用静态成员 - 否则,省略其创建)。

但是存在更深层次的问题。订单静态数据成员的声明。订单是他们的定义。请考虑以下

struct C { C() { printf("hey\n"); } };
struct A { 
  static C a;
  static C b;
};

C A::b;
C A::a;

在此代码中, b在之前创建,即使 a在b 之前声明。

以下代码打印2 1

struct C { C(int n) { printf("%d\n", n); } };

template<int N>
struct A {
  static C c;
};

template<int N>
C A<N>::c(N);

// explicit instantiation of declaration and definition
template struct A<2>;
template struct A<1>;

int main() {

}

但是以下代码不打印任何内容,除非您在main中的行中发表评论。

struct C { C(int n) { printf("%d\n", n); } };

template<int N>
struct A {
  static C c;
};

template<int N>
C A<N>::c(N);

// implicit instantiation of declarations
A<2> a2;
A<1> a1;

int main() {
  // A<1>::c; A<2>::c;
}

我真的不确定第二个片段的正确输出是什么。阅读标准,我无法确定订单。它在14.6.4.1“实例化点”中说:

  

对于函数模板特化,成员函数模板特化,或成员函数或类模板的静态数据成员的特化,如果特化是隐式实例化的,因为它是从另一个模板特化中引用的[... ]。否则,这种特化的实例化点紧跟在引用特化的命名空间范围声明或定义之后。

main的定义之后,它们的定义的实例化都会立即出现。在另一个定义似乎未指定之前实例化了哪个定义。如果有人知道答案并且khow其他编译器的行为(GCC打印1 2但是main交换的表达式的顺序,打印2 1),请在评论中告诉我。 / p>

有关详细信息,请参阅this answer about static object's lifetime

答案 1 :(得分:0)

您实际上并没有声明该代码中的任何对象。

您需要额外的代码:

s0 one;
s1 two;

在这种情况下,现在实际声明了两个对象,并且应该可以正常工作。

您是否明确声明了s0?

尝试使用s0虚拟跟随typedef;并查看问题是否已解决。