Нет определения для статического члена const с инициализатором? - PullRequest
3 голосов
/ 17 февраля 2011

Дано:

template<class T>
struct S {
  static int const N = 1;
};

extern template class S<int>;

template<class T>
int f( T n ) {
  return n + S<T>::N; // line 10
}

int main() {
  return f(1);        // line 14
}

//template class S<int>; // intentionally commented out to trigger error

Я получаю:

foo.cpp: In function ‘int f(T) [with T = int]’:
foo.cpp:10:   instantiated from ‘const int S<int>::N’
foo.cpp:10:   instantiated from ‘int f(T) [with T = int]’
foo.cpp:14:   instantiated from here
foo.cpp:10: error: explicit instantiation of ‘S<int>::N’ but no definition available

Но почему я получаю ошибку?

  1. Смысл явного объявления экземпляра шаблона заключается в том, что определения могут быть в другом месте , однако компилятор (не компоновщик) выдает ошибку. (В реальном приложении закомментированное в настоящий момент явное объявление экземпляра в любом случае будет находиться в другом модуле перевода.)
  2. В этом случае значение имеет константу-инициализатор , поэтому теоретически компилятор может просто напрямую использовать значение.
  3. Когда я не делаю явного объявления создания шаблона, мне (как ни странно) не нужно явно определять S<T>::N.

Это с g ++ 4.2.1 на Mac OS X 10.6.6.

Ответы [ 2 ]

2 голосов
/ 17 февраля 2011

От 9.4.2 / 2:

Объявление статических данных член в своем определении класса не определение и может быть неполный тип, кроме cvqualified недействительным. Определение для статических данных член должен появиться в пространстве имен область действия, охватывающая класс члена определение. В определении на область имен, имя член статических данных должен быть квалифицирован по имени класса, используя :: оператор.

А из 9.4.2 / 4:

Если элемент статических данных имеет постоянную целочисленный или константный тип перечисления, его объявление в классе определение может указать constantinitializer, который должен быть интегральное постоянное выражение (5.19). В этом случае член может появиться в интегральные константные выражения внутри его сфера применения. Член все еще должен быть определяется в области имен пространства, если это используется в программе и пространстве имен определение объема не должно содержать инициализатор.

Из этих ссылок мы можем сделать вывод ("... все равно будет определено ..." в 9.4.2 / 4), что если оно не определено, то программа не является корректной.

2 голосов
/ 17 февраля 2011
extern template class S<int>;

Я думаю, что эта строка вызывает ошибку, поскольку она указывает компилятору искать явное создание экземпляра из S<int>, но явного создания не существует. Отсюда и ошибка.

Как только вы прокомментируете эту строку, я думаю, что код должен хорошо скомпилироваться.


EDIT:

Хорошо, посмотрите на это: http://www.ideone.com/oQnOi

Как я уже сказал, он прекрасно компилируется!


EDIT:

Я думаю, что $ 9.4.2 / 4 (как указано Mark B ) не применяется к статическим членам класса templates , как $ 14.5.1.3 [temp.static] не требует, чтобы статические члены определялись в области имен:

Определение статического члена данных может быть предоставлено в области имен включая определение статического шаблон класса участника .

Пример выглядит следующим образом:

template<class T> class X  { static T s; }; 
template<class T> T X<T>::s = 0;

Обратите внимание, в нем не сказано, что "должно быть предоставлено" , скорее, "может быть предоставлено" . Поэтому я думаю, что определение статических членов шаблона класса в области имен пространства является необязательным.

...