我可以从类型列表中声明模板特化吗?

时间:2015-09-07 18:23:53

标签: c++ templates metaprogramming template-specialization

很确定我已经知道答案,但值得一试。

所以,说我有一个类型列表:

template <typename ...Ts>
struct typelist{};

包含一些对象:

struct foo{};
struct bar{};
struct quux{};

using objects = typelist<foo, bar, quux>;

现在我有一个模板化的类(baz)可以接受任何这些对象。但是,由于代码库大小和编译时间,我希望在cpp文件中实现我的模板化方法。

所以在baz.cpp的底部我有:

template <> class baz<foo>;
template <> class baz<bar>;
template <> class baz<quux>;

问题是我有很多类,如baz,他们使用的对象列表也在不断变化。那么......无论如何我可以保留我的单个对象类型列表并在每个baz的cpp文件中使用它 - 像对象一样专门化吗?然后,当我有一个新对象并且所有目标文件都将重建时,我所要做的就是更新我的类型列表。

5 个答案:

答案 0 :(得分:10)

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类型施加额外的要求。关键是要在必须实例化的上下文中使用类型,包括其所有方法。

答案 1 :(得分:3)

我很确定如果不使用预处理器,这是不可能的。您可能能够从参数重构模板参数包,但您必须实际传递参数的实例,这似乎是次优的。其次,在块范围内(即在模板函数中)不允许显式模板实例化,因此无法编写显式实例化另一个模板的模板。

如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。

答案 2 :(得分:3)

首先要做的事情:显式类模板实例化的正确语法是

template class baz<foo>;
template class baz<bar>;
template class baz<quux>;

不是template <> class baz<foo>,它是显式类模板特化(forward-declaration)。

一种可能性是实例化一个看起来像这样的类

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 ++中无法通过typelist的{​​{1}}外部世界中的模板参数进行迭代。typelist&#34;

另一种可能是使用宏,但即使在宏中,您也无法使用原始typelist。我会在给定typelist的情况下得出结论,问题无法解决。

作为解决方案,如果可能的话,我会在编译器上保留模板实例化。在这种情况下,未实例化的模板不会被实例化。编译速度慢是由于meta-programs are specified

的方式

答案 3 :(得分:2)

与普通预处理器配合使用的版本

//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

答案 4 :(得分:1)

这样就可以了。最终只有一种(或没有)类型的类型列表。

template <typename Head, typename ...Tail>
struct typelist{
    typedef baz<Head> head_t;
    typedef typelist<Tail...> tail_t;
};