簡體   English   中英

我可以從類型列表中聲明模板特化嗎?

[英]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這樣的類,它們使用的對象列表也在不斷變化。 所以......無論如何我可以保留我的單一對象類型列表並在每個baz的 cpp 文件中使用它 - 比如 object 來專門化? 然后,當我有一個新的 object 並且所有 object 文件將重建時,我所要做的就是更新我的類型列表。

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類型提出額外的要求。 關鍵是在必須實例化的上下文中使用類型,包括其所有方法。

我很確定如果不使用預處理器,這是不可能的。 您可能能夠從參數重構模板參數包,但您必須實際傳遞參數的實例,這似乎是次優的。 其次,在塊作用域(即模板函數)中不允許顯式模板實例化,因此無法編寫明確實例化另一個模板的模板。

如Nir所示,為什么不使用X宏呢?

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

首先要做的事情是:顯式類模板實例化的正確語法是

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從“的外界typelist ”。

另一種可能是使用宏,但即使在宏中,您也無法使用原始typelist 我會斷定你的問題沒有解決給定的typelist

作為解決方案,如果可能的話,我會在編譯器上保留模板實例化。 在這種情況下,未實例化的模板不會被實例化。 編譯速度慢是由於指定元程序的方式。

與普通預處理器一起使用的版本

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

這樣就可以了。 最終只有一種(或沒有)類型的類型列表。

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

如果您不能修改現有的類型列表(如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 ,但希望這種情況不會太頻繁,現代編譯器應該能夠告訴您應該將值更改為什么。 您甚至可以在構建系統中生成它並將其傳遞到編譯器命令行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM