2016-01-24 6 views
5

Я хочу переслать объявление переменных шаблонов в файл заголовка, а затем иметь фактические экземпляры в отдельном блоке компиляции.Невозможно объявить переменную шаблона без его определения

Мне повезло, что переменные шаблоны C++ 14 действовали очень как статические переменные класса. К сожалению, это, похоже, не совсем так, и это мешает мне переслать объявление переменных.

template <typename T> struct Variable { 
    static int variable; 
}; 

template <typename T> 
extern int variable; 

int main() { 
    (void) Variable<char>::variable; 
    // (void) variable<char>;     // <-- line 10 
} 

template <> int Variable<char>::variable = 42; 
template <> int variable<char> = 23; 

Образец, приведенный выше, компилируется и запускается как-находится под GCC. Но недопустимая строка 10 дает ошибку времени компиляции:

specialization of 'variable<char>' after instantiation 
    template <> int variable<char> = 23; 
        ^
+1

Clang отклоняет оба. Это плохо сформированный НДР. Явная * инстанция * и явная * специализация * - совершенно разные звери. –

+0

Все в порядке - так как * do * Я выполняю то, что хочу, - чтобы объявить переменную в заголовке, но определить ее в .cpp? –

ответ

1

Я думаю, что вы на правильном пути.

Хитрость такова: в любой единицы перевода не создавайте экземпляр шаблона до вашей специализации.

Например:

// test.h 
#ifndef TEST_H 
#define TEST_H 

template <typename T> 
extern int variable; 

template <> extern int variable<char>; 
template <> extern int variable<int>; 

#endif // TEST_H 

Тогда:

// test2.cpp 
#include "test.h" 

template <> int variable<char> = 23; 
template <> int variable<int> = 24; 

И наконец:

// test.cpp 
#include "test.h" 
#include <iostream> 

int 
main() 
{ 
    std::cout << variable<char> << '\n'; 
    std::cout << variable<int> << '\n'; 
} 

Для меня это выходы:

23 
24 

Обновление

T.C. указывает в комментариях ниже, что специализации должны быть объявлены перед первым использованием, поэтому я обновил «test.h» выше, чтобы сделать это.

Update 2

Там, кажется, некоторые реализации дивергенции. лязг, кажется, справиться с этим штраф:

template <typename T> 
extern int variable; 

template <> extern int variable<char>; 
template <> extern int variable<int>; 

#include <iostream> 

int 
main() 
{ 
    std::cout << variable<char> << '\n'; 
    std::cout << variable<int> << '\n'; 
} 

template <> int variable<char> = 23; 
template <> int variable<int> = 24; 

http://melpon.org/wandbox/permlink/DGYKvvoPbmRIHaFi

Однако НКУ дает ошибку:

prog.cc:4:13: error: explicit template specialization cannot have a storage class 
template <> extern int variable<char>; 
      ^~~~~~ 

prog.cc:5:13: error: explicit template specialization cannot have a storage class 
template <> extern int variable<int>; 
      ^~~~~~ 

Я искал стандарт и список основных вопросов, и я не могу найти все, что указывает на один компилятор или другой, является правильным. Если кто-то видит такие доказательства, я рад включить его в этот ответ.

+0

Это все еще [плохо сформированный NDR] (http://eel.is/c++draft/temp.expl.spec#6). Необходима декларация явной специализации в заголовке, хотя я не уверен, что OP фактически означает явно специализировать шаблон в первую очередь. –

+0

@ T.C .: Спасибо, исправлено. –

+0

Это все еще не работает - вот код. https://github.com/rec/variable-template. Это не будет работать на clang; на g ++ 5.3.0 он компилирует, но печатает 0 и 0; сборка «единства» также не компилируется. –