Как создать псевдоним, объявить и инициировать все вместе - PullRequest
0 голосов
/ 04 января 2019

У меня есть случаи, когда я делаю псевдоним для конкретного экземпляра шаблона.В моем коде, предшествующем c ++ 11, это было, например:

typedef std::vector<std::string> My;

Но я хочу использовать новые языковые возможности для создания только одного экземпляра.Это было бы:

template class std::vector<std::string>;//in source file
extern template class std::vector<std::string>;//in header file
using My = std::vector<std::string>;//in header file

У меня есть длинный список таких typedef в одном заголовочном файле (они все в одном контексте).Есть ли способ сделать это, не повторяя каждый шаблон 3 раза?

1 Ответ

0 голосов
/ 04 января 2019

Нет хорошего способа сделать это в C ++, но есть хакерский способ.Это никоим образом не рекомендуется, если только альтернатива не очень высока.

Идея состоит в том, чтобы использовать макросы C ++ - 11 (обычно это плохая идея):

#define DECLARE_AND_ALIAS(Alias, TemplateStart, ...) \
   extern template class TemplateStart __VA_OPT__(,)  __VA_ARGS__; \
   using Alias = TemplateStart __VA_OPT__(,) __VA_ARGS__

Они определяютдве вещи, которые вам нужны в заголовочном файле.Теперь ваш пример выглядит так:

template class std::vector<std::string>;//in source file
DECLARE_AND_ALIAS(My, std::vector<std::string>); //in header file

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

#ifdef INSTANTIATE_TEMPLATE
#  define DECLARE_AND_ALIAS(Alias, TemplateStart, ...) \
     template class TemplateStart __VA_OPT__(,) __VA_ARGS__; \
     using Alias = TemplateStart __VA_OPT__(,)  __VA_ARGS__
#else
#  define DECLARE_AND_ALIAS(Alias, TemplateStart, ...) \
     extern template class TemplateStart __VA_OPT__(,) __VA_ARGS__; \
     using Alias = TemplateStart __VA_OPT__(,) __VA_ARGS__
#endif

Теперь это несовершенно, так какВы не контролируете, для каких шаблонов генерировать код, а какие избегать.Для мелкозернистого решения вещи становятся грязными.Вы можете передать третий параметр, который будет отвечать за использование ключевого слова extern:

#define DECLARE_AND_ALIAS(Extern, Alias, TemplateStart, ...) \
     Extern template class TemplateStart __VA_OPT__(,) __VA_ARGS__; \
     using Alias = TemplateStart __VA_OPT__(,) __VA_ARGS__

И использование

#define MyExtern // compiling My.cpp
#define My2Extern extern // not compiling My2.cpp
DECLARE_AND_ALIAS(MyExtern, My, std::vector<std::string>);
DECLARE_AND_ALIAS(My2Extern, My2, std::map<int, std::string>);

Это только едва соответствует требованиямвопросы, но он использует переменные макропараметры C ++ 11.Это не чистое решение и, вероятно, не то, на что вы рассчитывали.

Когда будут введены модули (возможно, C ++ 20, но, возможно, только в C ++ 23), весь этот extern трюк исчезнет., поскольку ключевое слово import будет работать правильно в отношении генерации кода шаблонов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...