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

ev7lccsx  于 2023-02-06  发布在  其他
关注(0)|答案(6)|浏览(237)

我很确定我已经知道答案了,但值得一试。
假设我有一个类型列表:

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文件中使用它来进行专门化?然后,我所要做的就是在我有一个新对象时更新我的类型列表,所有的对象文件都将重建。

bbmckpt7

bbmckpt71#

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

nimxete2

nimxete22#

我敢肯定,如果不使用预处理器,这是不可能的。你可以从一个参数重构模板参数包,但你必须实际传递一个参数的示例,这似乎是次优的。其次,显式模板示例化不允许在块作用域(即在模板函数中),所以没有办法编写一个模板显式示例化另一个模板。
正如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即可。

gzszwxb4

gzszwxb43#

先做重要的事:显式类模板示例化的正确语法为

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

而不是template <> class baz<foo>template <> class baz<foo>是显式类模板专用化(前向声明)。
一种可能是示例化如下所示的类

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的外部世界"通过typelist中的模板参数进行迭代。
另一种可能是使用宏,但即使在宏中,你也不能使用你原来的typelist。我可以得出结论,你的问题没有解决给定的typelist
作为一个解决方案,如果可能的话,我会把模板示例化留在编译器上。在这种情况下,未使用的模板不会被示例化。编译速度慢是由于meta-programs are specified.

fnatzsnv

fnatzsnv4#

与普通预处理器一起使用的版本

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

8qgya5xd5#

这样就可以了,最终只使用一个(或没有)类型的类型列表的特殊化。

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

koaltpgm6#

如果你不能修改现有的类型列表(如https://stackoverflow.com/a/33084314/567292),但可以合理地确定它的长度不会改变,你仍然可以使用Boost.Preprocessor沿着Boost.MP11:

#define OBJECTS_SIZE 3  // adjust as necessary
static_assert(boost::mp11::mp_size<objects>::value == OBJECTS_SIZE);
#define INSTANTIATE_BAZ(z, N, _) template class baz<boost::mp11::mp_at_c<objects, N>>;
BOOST_PP_REPEAT(OBJECTS_SIZE, INSTANTIATE_BAZ, _)

每当类型列表的长度改变时,宏OBJECTS_SIZE就需要调整,但希望这种情况不会太频繁,现代编译器应该能够告诉你值应该改变为什么,你甚至可以在构建系统中生成它,并在编译器命令行中传递它。

相关问题