我想使用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
定義的主類模板。
gcc 4.7中的主要模板定義是格式不正確的NDR,因此無法在標準C++中解決它,因爲任何具有該模板定義的程序都已經格式不正確。請參閱http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1483 – Brian
4.7在這種情況下剛剛斷開,不確定是否有任何可以解決的問題。升級到4.8。或5.2。 – Barry
C++ 11標準庫還有其他領域,gnu編譯器套件直到最近纔開始工作。正則表達式直到4.9才工作,本地化直到5.1。最好的建議:更新你的編譯器。 –