2015-02-26 2 views
2

В следующем коде библиотеки:C++ инициализация: порядок Const глобального против статического члена класса

#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 сначала, как ожидалось.)

ответ

3

Простой ответ нет. Нет никаких гарантий. Если ClassB<I> ClassA<I>::b = ClassB<I>() не были шаблоном, была бы гарантия, поскольку обе они были в одной и той же единицы перевода, но эта гарантия перестает существовать, если статичность является членом класса шаблона (предположительно потому, что фактическое инстанцирование может быть в любой единицы перевода) ,

В данном конкретном случае, однако: почему извилистый способ получения константы pi. Просто:

double const pi = 3.1415926535897932384626433832795; 

должно быть достаточно. (Если у вас есть какие-либо сомнения для какой-либо из целевых машин, добавьте больше цифр, но это больше, чем нужно для получения максимально точного представления для IEEE.) И поскольку это статическая инициализация, это гарантировано любая динамическая инициализация имеет место.

0

Как говорит Джеймс Канзе, ответ отрицательный, заказ не может быть гарантирован (хотя ClassA<3> явно инстанцируется внутри единицы перевода). This answer содержит более подробную информацию о проблеме.

Одним из решений является является специализироваться статической переменной-члена в .cpp файле библиотеки, с

template<> 
ClassB<3> ClassA<3>::b = ClassB<3>(); 

вместо установки шаблона с template class ClassA<3>;.

Спецификация C++ 03. не говорит об этом явно, но спецификация C++ 11. является более четким в выпуске:

Определения явно специализированных шаблонов шаблонов шаблонов классов заказали инициализацию. Элементы статических данных шаблона другого класса (т. Е. Неявно или явно созданные экземпляры) имеют неупорядоченную инициализацию .

Смежные вопросы