2015-12-22 65 views
3

我想使用SFINAE(與void_t)來確定類模板特化或實例化是否具有定義的某個成員類型。然而,主要類模板的正文中有static_assert。 是否有可能在不修改主模板的情況下檢索此信息,並且沒有preprocessor tricks如何避免使用SFINAE時觸發static_assert?

#include <type_traits> 

template <class T> 
struct X { 
    static_assert(sizeof(T) < 0, ""); 
}; 

template <> 
struct X<int> { 
    using type = int; 
}; 

template <class...> 
using void_t = void; 

template <class, class = void_t<>> 
struct Has : std::false_type {}; 

template <class T> 
struct Has<T, void_t<typename T::type>> : std::true_type {}; 

int main() { 
    static_assert(Has<X<int>>::value == true, ""); 

    // How to make this compile? 
    static_assert(Has<X<char>>::value == false, ""); // ERROR 
} 

X<int>是一個明確的分工,雖然X<char>是主模板的隱式實例。當編譯器創建這個實例化時,整個SFINAE機器停止,並在主模板主體內發出static_assert聲明導致的錯誤。


我的具體動機是這樣的:我創建一個通用的包裝類模板,我想定義一個哈希函數,如果它的模板類型參數對std::hash<>專業化。但是,gcc 4.7在std::hash<>的主模板的定義內放置static_assert。 gcc 4.8和libvm的libC++的libstdC++只是聲明的主要模板。因此,我的類模板不適用於gcc/libstdC++ 4.7。

// GCC 4.7.2 
    /// Primary class template hash. 
    template<typename _Tp> 
    struct hash : public __hash_base<size_t, _Tp> 
    { 
     static_assert(sizeof(_Tp) < 0, 
      "std::hash is not specialized for this type"); 
     size_t operator()(const _Tp&) const noexcept; 
    }; 

// GCC 4.8.2 
    /// Primary class template hash. 
    template<typename _Tp> 
    struct hash; 

這個問題類似於this one,但我並不滿足於接受的答案在那裏。因爲在這裏我們不能「補丁」來匹配static_assert「,因爲一旦主模板被任何類型參數實例化,斷言總是會失敗。

編輯:上面我描述了具體的動機,爲抽象問題提供上下文,這是明確提出的。這個具體的動機是指gcc 4.7,但是請在評論和回答中儘量獨立於libstdC++ 4.7的實現細節。這只是一個例子。可以有任何種類的C++庫,其中可能具有類似於X定義的主類模板。

+0

gcc 4.7中的主要模板定義是格式不正確的NDR,因此無法在標準C++中解決它,因爲任何具有該模板定義的程序都已經格式不正確。請參閱http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1483 – Brian

+0

4.7在這種情況下剛剛斷開,不確定是否有任何可以解決的問題。升級到4.8。或5.2。 – Barry

+0

C++ 11標準庫還有其他領域,gnu編譯器套件直到最近纔開始工作。正則表達式直到4.9才工作,本地化直到5.1。最好的建議:更新你的編譯器。 –

回答

2

我真的不這麼認爲。 static_assert在類級別上下文中是爲了確保您永遠不會使用它無法處理的類型實例化類。它是爲了避免當你使用一種沒有實現預期概念的類型實例化一個類時產生的遠程問題,但是直到你打出一個使用了某些預期的東西的電話,或者更糟的是,然後在維護過程中出現。

因此static_assert意味着只要您嘗試實例化類,就像您正在嘗試做的那樣。

儘管有一個選項可以考慮:可以用來避免該問題的外部類。基本上,一個特質類可能會默認一些簡單的實現,但會覆蓋X<T>。這可能會非常脆弱,但我不知道如果不認真考慮其他選項(如更改問題類),我會將其引入具有長生命週期的事物中。

相關問題