在某些情况下,我会为特定模板实例创建别名。 在我的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次?
答案 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关键字将对代码的生成做出正确的选择模板。