代码之家  ›  专栏  ›  技术社区  ›  Sam Kellett

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

  •  8
  • Sam Kellett  · 技术社区  · 10 年前

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

    所以,假设我有一份打字列表:

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

    包含一些对象:

    struct foo{};
    struct bar{};
    struct quux{};
    
    using objects = typelist<foo, bar, quux>;
    

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

    所以在集市的底部。cpp我有:

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

    问题是我有很多课 巴兹 ,并且他们使用的对象列表也在不断变化。所以……不管怎样,我可以保留我的单个对象类型列表,并在每个对象的cpp文件中使用它吗 巴兹 -喜欢专门化的对象吗?然后,我所要做的就是当我有了一个新对象时更新我的类型列表,所有的对象文件都将重新生成。

    5 回复  |  直到 10 年前
        1
  •  11
  •   Andrey Semashev    10 年前

    这个 template <> class baz<foo>; line forward声明了一个专门化,而不是模板实例化,我想这就是您想要的。

    我认为没有直接的方法可以做到这一点,你必须做一些元编程。您可以使用 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 类型重点是在必须实例化的上下文中使用该类型,包括其所有方法。

        2
  •  3
  •   Matthew    10 年前

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

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

        3
  •  3
  •   Community Mohan Dere    9 年前

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

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

    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 这个 打字列表 是一个已经专门化的模板,在C++中无法通过模板参数进行迭代 打字列表 来自“外部世界” 打字列表 ".

    另一种可能是使用宏,但即使在宏中也不能使用原始的 打字列表 我认为你的问题没有解决 打字列表 .

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

        4
  •  2
  •   AndreyS Scherbakov    10 年前

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

    //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
    
        5
  •  1
  •   prgasp77    10 年前

    这就行了。最终,只使用一个(或没有)类型对类型列表进行了序列化。

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