如何一起别名,声明和初始化

时间:2019-01-04 06:19:49

标签: c++ c++11 templates

在某些情况下,我会为特定模板实例创建别名。 在我的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 :(得分:0)

在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 and dllimport are handled

#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关键字将对代码的生成做出正确的选择模板。