2013-04-30 101 views
8

考慮一下:靜態斷言和SFINAE

template <typename T> 
struct hash 
{ 
    static_assert(false,"Not implemented."); 
}; 

struct unhashable {}; 

template <typename T> 
auto test(const T &t) -> decltype((*(hash<T> const *)nullptr)(t),int); 

void test(...); 

int main() 
{ 
    std::cout << std::is_same<decltype(test(std::declval<unhashable>())),void>::value; 
} 

除了明顯缺失的頭,這應該編譯?

換句話說,我詢問是否需要在推斷重載函數模板的返回值時終止decltype內部觸發的靜態斷言失敗以停止編譯,或者是否只是簡單地丟棄過載。

在gcc 4.7上,編譯失敗。我相當積極,雖然這將在gcc 4.8中編譯好(但不能在此刻檢查)。誰是對的?

+0

可能重複[我如何強制客戶端調用明確專用的模板而不是主模板?](http://stackoverflow.com/questions/16286303/how-can-i-force-a-client-to-call-一個明確專用的模板而不是t) – 2013-04-30 15:00:23

回答

12

在任何兼容的編譯器中,編譯必須失敗。

SFINAE規則基於聲明而不是定義。 (很抱歉,如果我在這裏使用了錯誤的術語),我的意思是這樣的:

對於類/結構:

template < /* substitution failures here are not errors */ > 
struct my_struct { 
    // Substitution failures here are errors. 
}; 

對於函數:

template </* substitution failures here are not errors */> 
/* substitution failures here are not errors */ 
my_function(/* substitution failures here are not errors */) { 
    /* substitution failures here are errors */ 
} 

另外,給定的模板參數集的struct/function不存在也受到SFINAE規則的約束。

現在static_assert只能出現在替換失敗是錯誤的區域,因此,如果它觸發,你會得到一個編譯器錯誤。

例如,下面將是一個錯誤的執行enable_if

// Primary template (OK) 
template <bool, typename T> 
struct enable_if; 

// Specialization for true (also OK) 
template <typename T> 
struct enable_if<true, T> { 
    using type = T; 
}; 

// Specialization for false (Wrong!) 
template <typename T> 
struct enable_if<false, T> { 
    static_assert(std::is_same<T, T*>::value, "No SFINAE here"); 
    // The condition is always false. 
    // Notice also that the condition depends on T but it doesn't make any difference. 
}; 

那就試試這個

template <typename T> 
typename enable_if<std::is_integral<T>::value, int>::type 
test(const T &t); 

void test(...); 

int main() 
{ 
    std::cout << std::is_same<decltype(test(0)), int>::value << std::endl; // OK 
    std::cout << std::is_same<decltype(test(0.0)), void>::value << std::endl; // Error: No SFINAE Here 
} 

如果刪除的enable_if專業化爲false然後將代碼編譯和輸出

1 
1 
+0

謝謝你的詳盡解釋,將答案標記爲已接受。 – bluescarni 2013-05-01 12:10:54

6

在gcc 4.7上,編譯失敗。我相當積極,雖然這將在gcc 4.8中編譯好(但不能在此刻檢查)。誰是對的?

靜態斷言中的條件不依賴於任何模板參數。因此,編譯器可以在解析模板時立即將其評估爲false,並意識到斷言應該觸發 - 無論您是否實際在其他地方實例化模板。

在任何編譯器上都應該如此。

+0

夠公平的,我將在一段時間內確切地檢查GCC 4.8上會發生什麼。如果static_assert()被視爲「替代失敗」或更嚴重的事情,那麼我猜潛在的問題是: – bluescarni 2013-04-30 16:06:08

+0

@bluescarni:這不是替代失敗,而是一個硬性錯誤,因爲它不會發生在[「直接上下文」](http://stackoverflow.com/questions/15260685/what-is-exactly-the -immediate-context-mentioned-the-c11-standard-for-whic)函數類型及其模板參數類型 – 2013-04-30 16:17:00

+0

@Andy。我相信'static_assert'中的條件不依賴於'T'的事實沒有任何區別。請看看我的答案,並隨時改進它。 – 2013-04-30 16:50:40