2010-01-22 43 views
6

我想知道C++ 0x是否提供任何內置功能來檢查可變參數模板的參數包是否包含特定類型。今天,boost ::: mpl :: contains可以用來完成這一點,如果你使用boost :: mpl :: vector來替代適當的可變參數模板。但是,它有嚴重的編譯時間開銷。我想,C++ 0x對std :: is_same有編譯器級別的支持。所以我在想,如果像下面這樣的泛化也支持這個編譯器。檢查C++ 0x參數包是否包含類型

template <typename... Args, typename What> 
struct is_present 
{ 
    enum { value = (What in Args...)? 1 : 0 }; 
}; 

回答

3

不,你必須使用帶有可變參數模板(部分)專門做編譯時的計算是這樣的:

#include <type_traits> 

template < typename Tp, typename... List > 
struct contains : std::true_type {}; 

template < typename Tp, typename Head, typename... Rest > 
struct contains<Tp, Head, Rest...> 
: std::conditional< std::is_same<Tp, Head>::value, 
    std::true_type, 
    contains<Tp, Rest...> 
>::type {}; 

template < typename Tp > 
struct contains<Tp> : std::false_type {}; 

沒有爲可變參數模板只有另外一個內在的操作,那就是

template < typename... Types > 
struct typelist_len 
{ 
    const static size_t value = sizeof...(Types); 
}; 

你在哪裏得到「它有嚴重的編譯時間開銷」有:其計算參數列表例如長度sizeof操作符的特殊形式提升mpl從?我希望你不只是在這裏做出假設。 Boost mpl使用懶惰模板實例化等技術來嘗試減少編譯時間,而不是像天真模板元編程那樣爆炸。

+0

可能是一個更大的內部操作應該由語言/編譯器支持,而不僅僅是sizeof ....(4個點!)IMO,檢查存在與查找大小一樣是「基礎」。我覺得mpl的性能開銷是基於我寫的這個測試。 http://www.dre.vanderbilt.edu/~sutambe/files/mpl_intersection。cpp 我使用手動編碼的相交算法以及MPL的版本。 g ++ 4.4需要花費相同的時間來編譯兩者。 Variadic模板版本編譯速度提高了10倍。順便說一句,你可以請建議我讀一下關於mpl的懶惰模板實例化技術? – Sumant 2010-01-23 07:17:14

+0

我在C++ Template Metaprogramming書中發現了一些很好的惰性評估示例。這不是很明顯嗎?!不管怎麼說,多謝拉。 – Sumant 2010-01-23 07:25:50

+0

是的,你所要做的就是儘量避免模板實例化元函數(通過暴露嵌套類型別名類型「),然後再將結果提供給另一個增強元函數。Boost元函數設計用於評估元函數在最後一刻需要嵌套類型別名,你也應該嘗試避免使用裸值,並使用元數據類型包裝器(如mpl :: bool_),因爲它們也被設計爲延遲工作。 有時boost mpl提供 – 2010-01-23 10:10:07

2

如果您想避免手動類型遞歸,std::common_type在我看來是STL中唯一的實用程序,它是一個可變參數模板,因此它是唯一一個可能封裝遞歸的實用程序。


溶液1

std::common_type發現在一組類型的至少派生的類型。如果我們用類型來識別數字,特別是具有較少派生類型的高數字,它會找到一組中最大的數字。然後,我們必須將等同關係類型映射到一個推導級別。

using namespace std; 

struct base_one { enum { value = 1 }; }; 
struct derived_zero : base_one { enum { value = 0 }; }; 

template< typename A, typename B > 
struct type_equal { 
typedef derived_zero type; 
}; 

template< typename A > 
struct type_equal< A, A > { 
typedef base_one type; 
}; 

template< typename Key, typename ... Types > 
struct pack_any { 
enum { value = 
    common_type< typename type_equal< Key, Types >::type ... >::type::value }; 
}; 


解決方案2

我們可以破解common_type多一點。標準說

如果在 專業化 至少一個模板參數是用戶定義類型的程序可以專門此特徵。

並且準確地描述了它裏面的內容:遞歸部分專業化案例,應用二元運算符的案例和終端案例。實質上,它是一個通用的fold函數,您可以添加任何二進制操作。這裏我使用了另外,因爲它比OR更具信息性。請注意,is_same返回integral_constant

template< typename Addend > 
struct type_sum { // need to define a dummy type to turn common_type into a sum 
    typedef Addend type; 
}; 

namespace std { // allowed to specialize this particular template 
template< typename LHS, typename RHS > 
struct common_type< type_sum<LHS>, type_sum<RHS> > { 
    typedef type_sum< integral_constant< int, 
    LHS::type::value + RHS::type::value > > type; // <= addition here 
}; 
} 

template< typename Key, typename ... Types > 
struct pack_count : integral_constant< int, 
common_type< type_sum< is_same< Key, Types > > ... >::type::type::value > {}; 
+0

這是一個相當有頭腦的傳情。但我喜歡它!假設對common_type特徵有很好的理解。我不得不在C++ 0x公共草案中挖掘它。將它與通過type_equal隱式轉換爲base_one相結合是很聰明的。 C++有太多這些聰明的技巧。使用std :: is_same和邏輯 - 或者以某種方式可以做更直觀的事情嗎? – Sumant 2010-01-23 20:05:01

+0

@Sumant:是:v)。 – Potatoswatter 2010-01-23 20:44:01

+0

雖然稍微好一點,但仍然令人頭腦麻木的細節必須內化。 – Sumant 2010-01-23 23:16:21