2011-10-20 42 views
11

我目前正在做一些模板元編程。在我的情況下,我可以處理任何「迭代」類型,即任何類型,其中typedef foo const_iterator以相同的方式存在。我正在嘗試爲此使用新的C++ 11模板元編程,但是我無法找到檢測某種類型是否丟失的方法。在編譯時檢測typedef(模板元編程)

因爲我還需要根據其他特徵打開/關閉其他模板特化,所以我當前使用了一個帶有兩個參數的模板,第二個模板通過std::enable_if生成。這是我目前在做什麼:

template <typename T, typename Enable = void> 
struct Foo{}; // default case is invalid 

template <typename T> 
struct Foo< T, typename std::enable_if<std::is_fundamental<T>::value>::type>{ 
    void do_stuff(){ ... } 
}; 

template<typename T> 
struct exists{ 
    static const bool value = true; 
}; 

template<typename T> 
struct Foo<T, typename std::enable_if<exists< typename T::const_iterator >::value >::type> { 
    void do_stuff(){ ... } 
}; 

我不能做這樣的事,而不exists幫手模板。例如,只是在做

template<typename T> 
struct Foo<T, typename T::const_iterator> { 
    void do_stuff(){ ... } 
}; 

沒有工作,因爲在那些應該使用這種專業化的情況下,實例化了無效的默認情況。

但是我找不到這個exists在新的C++ 11標準中的任何地方,據我所知簡單地從boost::type_traits這種東西。然而homepageboost::type_traits沒有顯示任何可以用來代替的參考。

此功能缺失,還是我忽略了一些其他顯而易見的方式來實現所需的行爲?

回答

13

如果你只是想要一個給定的類型包含const_iterator然後下面是一個簡化的版本n您的代碼:

template<typename T> 
struct void_ { typedef void type; }; 

template<typename T, typename = void> 
struct Foo {}; 

template<typename T> 
struct Foo <T, typename void_<typename T::const_iterator>::type> { 
     void do_stuff(){ ... } 
}; 

請參閱this answer瞭解該技術的工作原理。

+3

你應該發佈一個關於這個如何工作的問題的鏈接。 :)另外,你似乎喜歡這個,看到你已經多次暗示它。 – Xeo

+0

@Xeo,是的,這很簡單直接。但我沒有得到你的第一部分'你也許應該發佈一個關於這個工作的問題的鏈接。':) ...你的意思是在回答時我應該把一個鏈接到我以前的問題(而不是代碼本身)?我懷疑這不是建議在SO上。 – iammilind

+1

Nono,我的意思是,你發佈一個鏈接到[你問的問題是如何工作的](http://stackoverflow.com/questions/6543652/different-template-syntax-for-finding-if-argument因爲它一開始並不明顯。 Woops,我剛纔注意到我寫了'問題',當然只意味着一個問題。 – Xeo

7

您可以創建一個特性has_const_iterator,它提供一個布爾值並在專業化中使用它。

像這樣的東西可能會做到這一點:

template <typename T> 
struct has_const_iterator { 
private: 
    template <typename T1> 
    static typename T1::const_iterator test(int); 
    template <typename> 
    static void test(...); 
public: 
    enum { value = !std::is_void<decltype(test<T>(0))>::value }; 
}; 

然後你就可以專注是這樣的:

template <typename T, 
      bool IsFundamental = std::is_fundamental<T>::value, 
      bool HasConstIterator = has_const_iterator<T>::value> 
struct Foo; // default case is invalid, so no definition! 

template <typename T> 
struct Foo< T, true, false>{ 
    void do_stuff(){// bla } 
}; 

template<typename T> 
struct Foo<T, false, true> { 
    void do_stuff(){//bla} 
}; 
+1

是否有您選擇'的理由測試(int)'而不是,例如'test()'?只要確保我理解重載解析在這裏是如何工作的。謝謝! – nknight

+2

@nknight:原因:使對'test'的調用明確無誤。 – erenon

4

這裏有一個成員類型特徵檢查的另一個版本:

template<typename T> 
struct has_const_iterator 
{ 
private: 
    typedef char      yes; 
    typedef struct { char array[2]; } no; 

    template<typename C> static yes test(typename C::const_iterator*); 
    template<typename C> static no test(...); 
public: 
    static const bool value = sizeof(test<T>(0)) == sizeof(yes); 
}; 
1

有幾種方法可以做到這一點。在C++ 03,你可以使用升壓和enable_if定義特徵(docssource):

BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator); 

template <typename T, typename Enable = void> 
struct Foo; 

template <typename T> 
struct Foo< T, typename boost::enable_if<boost::is_fundamental<T> >::type>{ 
    void do_stuff(){ ... } 
}; 

template<typename T> 
struct Foo<T, typename boost::enable_if<has_const_iterator<T> >::type> { 
    void do_stuff(){ ... } 
}; 

在C++ 11,你可以使用Tick這樣的:

TICK_TRAIT(has_const_iterator) 
{ 
    template<class T> 
    auto require(const T&) -> valid< 
     has_type<typename T::const_iterator> 
    >; 
}; 

template <typename T, typename Enable = void> 
struct Foo; 

template <typename T> 
struct Foo< T, TICK_CLASS_REQUIRES(std::is_fundamental<T>::value)>{ 
    void do_stuff(){ ... } 
}; 

template<typename T> 
struct Foo<T, TICK_CLASS_REQUIRES(has_const_iterator<T>())> { 
    void do_stuff(){ ... } 
}; 

而且使用Tick,您可以進一步增強特性以實際檢測到const_iterator實際上也是一個迭代器。所以說,我們定義一個簡單的is_iterator特點是這樣的:

TICK_TRAIT(is_iterator, 
    std::is_copy_constructible<_>) 
{ 
    template<class I> 
    auto require(I&& i) -> valid< 
     decltype(*i), 
     decltype(++i) 
    >; 
}; 

然後我們就可以定義has_const_iterator性狀檢查const_iterator類型is_iterator性狀這樣的匹配:

TICK_TRAIT(has_const_iterator) 
{ 
    template<class T> 
    auto require(const T&) -> valid< 
     has_type<typename T::const_iterator, is_iterator<_>> 
    >; 
};