2012-01-06 14 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_isnan_available :: value work? –

+0

@トニー:両方のために 'std :: isnan'がオーバーロードされています。そして、それでもfloatからdoubleへの暗黙の変換があります。それでも、私は二重のために試して試しても動作しません。 –

+0

@ TonyDelroy:良い考えですが、通常は標準の関数がオーバーロードされます。それでも、あなたはそれがまだ[ideone](http://www.ideone.com/U7EqO)で動作しないことを確認できます。 –

答えて

7

これは、usingディレクティブが現在の名前空間にメンバーを追加しないため、std::メンバがこの名前空間の宣言によって隠されている可能性があります。

using std::isnanは、インポートされた名前空間のメンバがuse -locationとインポートされた名前空間の両方を囲む名前空間に追加されたかのように動作します。 using宣言は名前空間の通常の宣言なので、続く宣言でオーバーロード解決に参加できます。

ただし、コメントに指摘されているように、関数が存在しない場合はエラーが発生します。この問題を回避するには、put it out of your detail:: namespace thenが必要です。インポートされた定義は、dummyと同じレベルになるため、うまくいくはずです。オーバーロードをグローバル名前空間に渡すことも、補助名前空間(グローバル名前空間で)とimport bothを作成することもできます。

+0

それは存在しなければ、ハードエラーを引き起こすだろう。 http://www.ideone.com/44sE3。私はそれが存在しないことを期待している場合、私は関数の名前を付けることができないので、 'using namespace'を持っています。 –

+0

これらの2つの間の名前の参照の点で違いは何かを説明できますか?直感的に私は 'namespaceを使うのはすぐにすべてのシンボルをインポートするためのショートカットだったと思っていましたが、私は確かに名前の参照の点で矛盾を期待していませんでした。 –

+0

ああ、それです!私はそれで 'std'から宣言を隠すことを知らなかった。ありがとう。 –

1

この問題は、スレッドセーフでない標準関数よりも優れたPOSIXスレッドセーフなAPIのセットで解決されました。C++11 alternative to localtime_rです。このコードは、APIがグローバル名前空間に定義されているかどうかを検出し、存在しない場合はカスタム回避策を選択します。

関連する問題