我可以从类型列表中声明模板特化吗?
Can I declare a template specialization from a typelist?
很确定我已经知道了这个问题的答案,但值得一试。
所以,假设我有一个类型列表:
template <typename ...Ts>
struct typelist{};
包含一些对象:
struct foo{};
struct bar{};
struct quux{};
using objects = typelist<foo, bar, quux>;
现在我有一个模板化的 class (baz
) 可以接受这些对象中的任何一个。但是,由于代码库大小和编译时间,我想在 cpp 文件中实现我的模板化方法。
所以在 baz.cpp 的底部我有:
template <> class baz<foo>;
template <> class baz<bar>;
template <> class baz<quux>;
问题是我有很多像 baz
这样的 classes,并且它们使用的对象列表也在不断变化。所以...无论如何我可以保留我的单个对象类型列表并在每个 baz
-like 对象的 cpp 文件中使用它来专门化吗?然后,当我有一个新对象时,我所要做的就是更新我的类型列表,所有的对象文件都会重建。
template <> class baz<foo>;
行向前声明了一个特化而不是模板实例化,我想这就是您想要的。
我认为没有直接的方法可以做到这一点,您必须进行一些元编程。您可以使用 Boost.Preprocessor 生成所有需要的代码:
#define TYPES (foo)(bar)(quux)
using objects = typelist< BOOST_PP_SEQ_ENUM(TYPES) >;
// Generate extern template declarations in the header
#define EXTERN_TEMPLATE_BAZ(r, data, arg)\
extern template class baz< arg >;
BOOST_PP_SEQ_FOR_EACH(EXTERN_TEMPLATE_BAZ, _, TYPES)
// Generate template instantiations in the .cpp
#define TEMPLATE_BAZ(r, data, arg)\
template class baz< arg >;
BOOST_PP_SEQ_FOR_EACH(TEMPLATE_BAZ, _, TYPES)
可能有一种方法可以在没有预处理器的情况下执行此操作,但这样做会对 baz
类型施加额外的要求。重点是在必须实例化它的上下文中使用该类型,包括它的所有方法。
我很确定如果不使用预处理器这是不可能的。您也许能够从一个参数重建模板参数包,但您必须实际传递一个参数实例,这似乎不是最佳选择。其次,在块范围内(即在模板函数中)不允许显式模板实例化,因此无法编写显式实例化另一个模板的模板。
正如 Nir 所说,你为什么不直接使用 X Macro?
#define MY_FOREACH_TYPES(func, ...) \
func(type1, ##_VA_ARGS__) \
func(type2, ##_VA_ARGS__) \
#define MY_INSTANTIATE(Type, Class) \
template <> class Class<Type>;
MY_FOREACH_TYPES(MY_INSTANTIATE, bar)
现在,当您的类型列表发生变化时,只需更新 MY_FOREACH_TYPES。
与普通预处理器一起工作的版本
//Header file
#define BAZ_OBJS \
BAZ_BEGIN foo \
BAZ_AND bar \
BAZ_AND quux \
BAZ_END
#define BAZ_BEGIN
#define BAZ_AND ,
#define BAZ_END
using objects = typelist<BAZ_OBJS>;
#undef BAZ_BEGIN
#undef BAZ_AND
#undef BAZ_END
#define BAZ_BEGIN BAZ_EXTERN template class baz<
#define BAZ_END >;
#define BAZ_AND BAZ_END BAZ_BEGIN
#ifdef MY_IMPLEMENTATION_CPP //cpp should define it before including the header file
#define BAZ_EXTERN
#else
#define BAZ_EXTERN extern
#endif
BAZ_OBJS
首先要做的事情是:显式 class 模板实例化的正确语法是
template class baz<foo>;
template class baz<bar>;
template class baz<quux>;
不是 template <> class baz<foo>
,它是显式 class 模板特化(前向声明)。
一种可能是实例化一个看起来像这样的class
template <template <typename> class T, typename... Args>
class for_each_class : T<Args>...
{
};
// Instantiate
template class for_each_class<baz, foo, bar, quux>;
这将强制 baz<foo>
、baz<bar>
、baz<quux>
的隐式实例化。好吧,但是您想从 typelist
创建它。 typelist
是一个已经专门化的模板,在 C++ 中无法通过 "outside world of typelist
".
中的 typelist
中的模板参数进行迭代
另一种可能是使用宏,但即使在宏中你也不能使用原来的 typelist
。我会得出结论,你的问题没有解决给定 typelist
.
作为解决方案,如果可能的话,我会在编译器上保留模板实例化。在这种情况下,未使用的模板不会被实例化。编译速度慢是由于 meta-programs are specified.
的方式
这样就可以了。最终只有一种(或none)类型的类型列表的专业化。
template <typename Head, typename ...Tail>
struct typelist{
typedef baz<Head> head_t;
typedef typelist<Tail...> tail_t;
};
很确定我已经知道了这个问题的答案,但值得一试。
所以,假设我有一个类型列表:
template <typename ...Ts>
struct typelist{};
包含一些对象:
struct foo{};
struct bar{};
struct quux{};
using objects = typelist<foo, bar, quux>;
现在我有一个模板化的 class (baz
) 可以接受这些对象中的任何一个。但是,由于代码库大小和编译时间,我想在 cpp 文件中实现我的模板化方法。
所以在 baz.cpp 的底部我有:
template <> class baz<foo>;
template <> class baz<bar>;
template <> class baz<quux>;
问题是我有很多像 baz
这样的 classes,并且它们使用的对象列表也在不断变化。所以...无论如何我可以保留我的单个对象类型列表并在每个 baz
-like 对象的 cpp 文件中使用它来专门化吗?然后,当我有一个新对象时,我所要做的就是更新我的类型列表,所有的对象文件都会重建。
template <> class baz<foo>;
行向前声明了一个特化而不是模板实例化,我想这就是您想要的。
我认为没有直接的方法可以做到这一点,您必须进行一些元编程。您可以使用 Boost.Preprocessor 生成所有需要的代码:
#define TYPES (foo)(bar)(quux)
using objects = typelist< BOOST_PP_SEQ_ENUM(TYPES) >;
// Generate extern template declarations in the header
#define EXTERN_TEMPLATE_BAZ(r, data, arg)\
extern template class baz< arg >;
BOOST_PP_SEQ_FOR_EACH(EXTERN_TEMPLATE_BAZ, _, TYPES)
// Generate template instantiations in the .cpp
#define TEMPLATE_BAZ(r, data, arg)\
template class baz< arg >;
BOOST_PP_SEQ_FOR_EACH(TEMPLATE_BAZ, _, TYPES)
可能有一种方法可以在没有预处理器的情况下执行此操作,但这样做会对 baz
类型施加额外的要求。重点是在必须实例化它的上下文中使用该类型,包括它的所有方法。
我很确定如果不使用预处理器这是不可能的。您也许能够从一个参数重建模板参数包,但您必须实际传递一个参数实例,这似乎不是最佳选择。其次,在块范围内(即在模板函数中)不允许显式模板实例化,因此无法编写显式实例化另一个模板的模板。
正如 Nir 所说,你为什么不直接使用 X Macro?
#define MY_FOREACH_TYPES(func, ...) \
func(type1, ##_VA_ARGS__) \
func(type2, ##_VA_ARGS__) \
#define MY_INSTANTIATE(Type, Class) \
template <> class Class<Type>;
MY_FOREACH_TYPES(MY_INSTANTIATE, bar)
现在,当您的类型列表发生变化时,只需更新 MY_FOREACH_TYPES。
与普通预处理器一起工作的版本
//Header file
#define BAZ_OBJS \
BAZ_BEGIN foo \
BAZ_AND bar \
BAZ_AND quux \
BAZ_END
#define BAZ_BEGIN
#define BAZ_AND ,
#define BAZ_END
using objects = typelist<BAZ_OBJS>;
#undef BAZ_BEGIN
#undef BAZ_AND
#undef BAZ_END
#define BAZ_BEGIN BAZ_EXTERN template class baz<
#define BAZ_END >;
#define BAZ_AND BAZ_END BAZ_BEGIN
#ifdef MY_IMPLEMENTATION_CPP //cpp should define it before including the header file
#define BAZ_EXTERN
#else
#define BAZ_EXTERN extern
#endif
BAZ_OBJS
首先要做的事情是:显式 class 模板实例化的正确语法是
template class baz<foo>;
template class baz<bar>;
template class baz<quux>;
不是 template <> class baz<foo>
,它是显式 class 模板特化(前向声明)。
一种可能是实例化一个看起来像这样的class
template <template <typename> class T, typename... Args>
class for_each_class : T<Args>...
{
};
// Instantiate
template class for_each_class<baz, foo, bar, quux>;
这将强制 baz<foo>
、baz<bar>
、baz<quux>
的隐式实例化。好吧,但是您想从 typelist
创建它。 typelist
是一个已经专门化的模板,在 C++ 中无法通过 "outside world of typelist
".
typelist
中的模板参数进行迭代
另一种可能是使用宏,但即使在宏中你也不能使用原来的 typelist
。我会得出结论,你的问题没有解决给定 typelist
.
作为解决方案,如果可能的话,我会在编译器上保留模板实例化。在这种情况下,未使用的模板不会被实例化。编译速度慢是由于 meta-programs are specified.
的方式这样就可以了。最终只有一种(或none)类型的类型列表的专业化。
template <typename Head, typename ...Tail>
struct typelist{
typedef baz<Head> head_t;
typedef typelist<Tail...> tail_t;
};