2012-01-06 98 views
8

我試圖想出一個黑客來測試std::isnan是否在預處理器中沒有特殊的套管編譯器的情況下定義的,並且提出了以下內容,我期望它能夠正常工作。SFINAE從另一個命名空間測試一個免費函數

#include <cmath> 
#include <type_traits> 

namespace detail { 
    using namespace std; 

    struct dummy {}; 
    void isnan(dummy); 

    //bool isnan(float); // Just adding this declaration makes it work! 

    template <typename T> 
    struct is_isnan_available { 
     template <typename T1> 
     static decltype(isnan(T1())) test(int); 
     template <typename> 
     static void test(...); 

     enum { value = !std::is_void<decltype(test<T>(0))>::value }; 
    }; 
} 

int main() { 
    return detail::is_isnan_available<float>::value; 
} 

變爲it doesn't detect it。我知道某些std::isnan是在ideone上定義的,因爲我手動測試過。

而當我uncomment the marked line above,它的工作原理。

我在這裏錯過了什麼?什麼解釋了這種行爲?

+0

好奇:is is_isnan_available ::價值工作? – 2012-01-06 11:00:55

+0

@Tony:'std :: isnan'對於兩者都是過載的。即使如此,還是有一個從float到double的隱式轉換。儘管如此,我嘗試過,雙測試也不起作用。 – 2012-01-06 11:03:29

+0

@TonyDelroy:好的想法,但是標準函數通常是超載的。仍然爲它,你可以檢查它仍然無法在[ideone](http://www.ideone.com/U7EqO) – 2012-01-06 11:04:40

回答

7

問題是,using指令不會將成員添加到當前名稱空間,因此std::成員仍可能被此名稱空間中的聲明隱藏。

using std::isnan會改變行爲,就好像導入的名稱空間的成員被添加到包含use位置和導入的名稱空間的名稱空間一樣。使用聲明是名稱空間中的正常聲明,因此可以使用隨後的聲明參與重載解析。

但是,正如評論中指出的那樣,如果該函數不存在,則會產生錯誤。要解決該問題,您需要put it out of your detail:: namespace then。這應該起作用,因爲導入的定義與dummy過載處於同一水平。您可以將重載帶入全局名稱空間,也可以創建輔助名稱空間(位於全局名稱空間中)和import both

+0

如果它不存在,會導致一個硬錯誤。 http://www.ideone.com/44sE3。我有'使用命名空間',因爲我不能命名該函數,如果我期望它不存在。 – 2012-01-06 11:06:11

+0

你能解釋一下這兩者之間在名稱查詢方面有什麼不同嗎?直覺上我以爲'使用名稱空間'只是一次性導入所有符號的快捷方式,我當然不會指望名稱查找的差異。 – 2012-01-06 11:06:58

+0

啊,就是這樣!我不知道我會用'std'來隱藏聲明。謝謝。 – 2012-01-06 11:19:35

1

我解決了這個問題,用於取代非線程安全標準函數的POSIX線程安全API集合:C++11 alternative to localtime_r。此代碼檢測API是否在全局名稱空間中定義,如果它不存在,則選擇自定義解決方法。

相關問題