2016-09-23 9 views
3

私はoperator[]のための簡単なチェックを書きましたが、has_subscript_op構造体テンプレートのインスタンスが間違ったオーバーロードを選択します:SFINAEの演算子[]のチェックが私よりも混乱していますか?

#include <iostream> 
#include <type_traits> 
#include <string> 
#include <map> 

template<class, class, class = void> 
struct has_subscript_op : std::false_type 
{ }; 

template<class T, class S> 
struct has_subscript_op<T, S, std::void_t<decltype(&std::declval<T>()[S()])>> : std::true_type 
{ }; 

int main() 
{ 
    //true, nice 
    std::cout << "int[][int]: " << has_subscript_op<int[], int>::value << std::endl; 
    //false, nice 
    std::cout << "int[][float]: " << has_subscript_op<int[], float>::value << std::endl; 
    //true, nice 
    std::cout << "std::string[int]: " << has_subscript_op<std::string, int>::value << std::endl; 
    //true, WAT? 
    std::cout << "std::map<std::string, std::string>[int]: " << has_subscript_op<std::map<std::string, std::string>, int>::value << std::endl; 
} 

私はGCC 6.2.0に

Coliru

を使用していますが、このGCCのバグ、一般的なバグです、または私はどこかに明白な間違いをした?

+1

私はgccを使いましたが、コンパイラで5〜6個のバグが見つかりました。与えられたコンパイルの失敗がコンパイラのバグの結果である可能性は非常に小さいです。 –

+0

'std :: map s; auto b = s [0]; ' - これはうまくコンパイルされ、あなたが見ている結果を説明します。さて、なぜ[0] 'が動作するのか、これは別の質問でしょう。 –

+0

@BaummitAugen最後の1つです。例のマップは 'operator [](int)'ではなく、 'operator [](std :: string)'を持っていなければなりません。 – xinaiz

答えて

8

だけ&をドロップすると、あまりにもキーのdeclvalを使用します。

template<class T, class S> 
struct has_subscript_op<T, S, std::void_t<decltype(std::declval<T>()[std::declval<S>()])>> : std::true_type {}; 

Live example at coliru

S()とのチェックが間違った結果を与えたのはなぜですか? GCCでは、それは0と考えられています。 std::stringはポインタで構築することができ、0はNULLポインタ定数になります。

他のコンパイラはS()をそのままC++で0として扱いません。

あなた自身のために試すことができます:それは、0はないので

std::map<std::string, std::string> test; 

// compile fine, segfault at runtime 
auto a = test[0]; 

// compile error! 
auto b = test[2] 

チェックがstd::declvalに良い作品でもない2が、平野int。ボーナスは、declvalで、あなたのチェックではキーをデフォルトで構成可能にする必要はありません。

+0

それは当てはまりません。それは参照に変換するのではなく、rvalue参照を使用して、 'int&'を許可するために折りたたみを使用します。しかし、 'std :: declval ()'は 'int &&'型を返します。これには他の規則が適用されています。 –

+1

ありがとうございます。一定。 –

+6

実際、これはバグです。リテラルゼロだけがC++のヌルポインタ定数です14。 'S()'はそうではありません。 –

関連する問題