如何保证模板结构中const静态成员的初始化排序

时间:2012-06-27 21:11:47

标签: c++ templates initialization static-members static-initialization

我有两个模板化结构,每个结构都包含一个const静态成员变量。其中一个成员变量的初始化取决于第二个。因此,我希望能够保证第二个在第一个之前初始化。这是一个简化的例子:

dependency.hpp:

template<typename T, T> struct value { };

template <typename T>
struct Dependency {
  Dependency() {}
  Dependency(T v) : var(v) {}
  const static Dependency staticVar;
  T var;
};

template <typename T>
const Dependency<T> Dependency<T>::staticVar = Dependency<T>(1.5);

testStruct.hpp:

#include "dependency.hpp"

//template class Dependency<double>; [1]
//template class Dependency<float>;  [2]

template <typename T>
struct TestStruct {
  TestStruct(Dependency<T> v) : var(v.var) {}

  const static TestStruct staticVar;
  T var;
};

template <typename T>
const TestStruct<T> TestStruct<T>::staticVar = TestStruct<T>(Dependency<T>(Dependency<T>::staticVar));

TEST.CPP:

#include <iostream>
#include "testStruct.hpp"

using namespace std;

int main(int argc, char *argv[])
{
  cout << "TestStruct<d> " << TestStruct<double>::staticVar.var << endl;
  cout << "Dependency<d> " << Dependency<double>::staticVar.var << endl;

  cout << endl;

  cout << "Dependency<f> " << Dependency<float>::staticVar.var << endl; // [3]
  cout << "TestStruct<f> " << TestStruct<float>::staticVar.var << endl;

  return 0;
};

main的输出是

TestStruct<d> 0
Dependency<d> 1.5

Dependency<f> 1.5
TestStruct<f> 1.5

也就是说,如果TestStruct<T>已经为类型staticVar实例化,则Dependency的{​​{1}}会被正确初始化,但是它仍然为0,因为{{ 1}}尚未初始化。取消注释[1]和[2]解决了类型TDependency<T>::staticVar的问题(即,所有输出1.5,即使[3]注释),但我希望如果可能不必列出所有可能的类型或在不使用它们的代码中实例化那些类型的模板。我希望能够在float(或double)中放置一些内容,以保证TestStruct<T>已经为该类型实例化,而无需指定T可能是什么类型。

我看过C++ Static member initalization (template fun inside)How to force a static member to be initialized?。第一个很好地解释了情况,但没有提出像我这样的问题的解决方案。第二个有两个解决方案,但似乎都没有在GCC 4.2.1中工作(或者我错误地应用了它......)。

我应该尝试其他技巧或解决方法,还是我坚持使用明确的实例化?

1 个答案:

答案 0 :(得分:1)

正如cdhowie所建议的那样,您可以使用静态方法来确保TestStructDependency之间的初始化顺序。如果您真的担心保持静态变量的外观而不是静态方法,则可以使用静态方法调用初始化的静态引用变量。

您只需要确保静态方法实现本身不使用静态引用变量,以便在全局初始化上下文中安全地调用它们。

template <typename T>
struct Dependency {
  Dependency() {}
  Dependency(T v) : var(v) {}
  static const Dependency & staticMethod () {
      static const Dependency staticMethodVar(1.5);
      return staticMethodVar;
  }
  static const Dependency & staticVar;
  T var;
};

template <typename T>
const Dependency<T> & Dependency<T>::staticVar
        = Dependency<T>::staticMethod();

template <typename T>
struct TestStruct {
  TestStruct(Dependency<T> v) : var(v.var) {}
  static const TestStruct & staticMethod () {
      static const TestStruct staticMethodVar(Dependency<T>::staticMethod());
      return staticMethodVar;
  }
  static const TestStruct & staticVar;
  T var;
};

template <typename T>
const TestStruct<T> & TestStruct<T>::staticVar
        = TestStruct<T>::staticMethod();