объявления `extern` и последующие определения экземпляров шаблона класса со списками параметров и без них - PullRequest
0 голосов
/ 26 сентября 2018

Рассмотрим следующий код:

template <typename T = int> struct X {};
extern X foo;
X foo;

Live на gcc.godbolt.org

Я ожидаю, что он будет правильно сформирован, но GCC, Clang и MSVC отклоняют его с помощью следующих сообщений об ошибках:

GCC 8.2 (с -std=c++17 -Wall -Wextra -pedantic-errors):

<source>:3:3: error: conflicting declaration 'X foo'
 X foo;
   ^~~
<source>:2:10: note: previous declaration as 'X<int> foo'
 extern X foo;
          ^~~

Clang 7.0.0 (с-std=c++17 -Wall -Wextra -pedantic-errors):

<source>:2:10: error: declaration of variable 'foo' with deduced type 'X' requires an initializer
extern X foo;
         ^

MSVC Pre 2018 (с /std:c++latest):

<source>(2): error C2641: cannot deduce template argument for 'X'
<source>(3): error C2133: 'foo': unknown size
<source>(3): error C2641: cannot deduce template argument for 'X'

Теперьинтересная часть.

Этот фрагмент принят Clang, но отклонен GCC & MSVC:

extern X<> foo;
X foo;

И этот фрагмент принят GCC, но отклонен Clang & MSVC:

extern X foo;
X<> foo;

Этот принят всеми тремя компиляторами:

extern X<> foo;
X<> foo;

И, наконец, этот принят GCC & Clang, но отклонен MSVC:

X foo;

Чтоздесь происходит?Какие из этих пяти фрагментов верны?

1 Ответ

0 голосов
/ 26 сентября 2018

лязг прав во всех пяти ваших отрывках.

extern X<> foo; // type: X<>
X foo; // CTAD => type: X<>

foo - это всего лишь объявление foo, которое затем повторно объявляется с тем же типом, поэтому gcc и MSVC неправильно отклоняют этот случай.

extern X foo; // invalid
X<> foo; // ok => type: X<>

GCC здесь не так.foo не является определением, это только объявление без инициализатора, и, следовательно, не является инициализирующим объявлением , как требуется для CTAD ( [dcl.class.type.deduct] ).

extern X<> foo; // type: X<>
X<> foo; // type: X<>

Это похоже на 1), только CTAD не требуется.Так как второй foo является просто переопределением foo и определяет его одновременно с тем же типом, он действителен.

X foo;

MSVC здесь не так,Стандарт не накладывает никаких ограничений на CTAD в глобальной области видимости.

В заключение, мы можем заключить, что ваш исходный фрагмент неверно сформирован, поскольку вы используете CTAD для переменной, которая не определена.

...