2015-09-07 47 views
7

很確定我已經知道答案了,但它值得一試。我可以從類型列表中聲明模板專門化嗎?

所以,說我有一個類型串:

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文件中使用它來專門化?然後,我所要做的就是在我有一個新對象時更新我的​​類型列表,並重建所有對象文件。

+0

您不必*特殊化*,只顯式*實例化*它們。 – Jarod42

+0

這絕對可以使用宏來完成。鑑於這將與您的其他代碼庫隔離,爲什麼不這樣做呢? –

回答

9

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類型的附加要求。重點是在必須實例化的上下文中使用該類型,包括其所有方法。

+0

並非所有人都使用增強功能,並且沒有關於增強問題的提示。 –

+2

那麼?儘管如此,這仍是一個有效的解決方案。 –

+0

該解決方案有效,但可能並非提問者想要的。 Boost不是標準C++的一部分。 –

3

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

正如尼爾所示,爲什麼不使用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。

+0

非常感謝X-Macro的提及。維基鏈接是最好的!你知道什麼讓人們不使用X宏嗎? (除了它更難跟蹤/調試) – javaLover

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 
3

第一件事上班版本:正確的語法明確的類模板實例是

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創建這個。 typelist是一個已經專用的模板,並且C++無法通過typelist中的「typelist的外部世界」中的模板參數進行迭代。

另一種可能是使用宏,但即使在宏中也不能使用原來的typelist。我會斷定你的問題並沒有解決給定typelist

作爲解決方案,如果可能的話,我會在編譯器上留下模板實例。在這種情況下未使用的模板未實例化。緩慢的編譯是由於meta-programs are specified的方式。

+0

這不會實例化'baz ','baz '或'baz '。 – Barry

+0

因爲是模板的成員沒有實例化。 – Barry

+0

@Barry請再讀一遍我的文章。我並不是說這會實例化'baz '等,但我正在解釋爲什麼沒有宏就無法完成。 –

1

這會做到這一點。最終只用一種(或沒有)類型的類型化的secialization。

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

不,它沒有實例化'baz'。 –

+0

如果'baz '是'typelist '的屬性,該怎麼辦?我目前無法測試它;我得到的最新編譯器是gcc4.3。 – prgasp77

+0

什麼屬性?我沒有意識到任何執行模板實例化的屬性。 –

相關問題