c++ - const std:: string&をとる関数が0を受け入れないようにする




implicit-conversion (2)

千の言葉に値する:

#include<string>
#include<iostream>

class SayWhat {
    public:
    SayWhat& operator[](const std::string& s) {
        std::cout<<"here\n"; // To make sure we fail on function entry
        std::cout<<s<<"\n";
        return *this;
    }
};

int main() {
    SayWhat ohNo;
    // ohNo[1]; // Does not compile. Logic prevails.
    ohNo[0]; // you didn't! this compiles.
    return 0;
}

コンパイラは、文字列を受け入れるブラケット演算子に数値0を渡すときに文句を言いません。 代わりに、これはコンパイルされて、メソッドに入る前に失敗します:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

参考のために:

> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)

私の推測

コンパイラーは暗黙的に std::string(0) コンストラクターを使用してメソッドに入りますが、これは正当な理由もなく同じ問題(上記のエラーgoogle)をもたらします。

質問

とにかくこれをクラス側で修正する必要があるので、APIユーザーはこれを感じず、コンパイル時にエラーが検出されますか?

つまり、オーバーロードを追加する

void operator[](size_t t) {
    throw std::runtime_error("don't");
}

良い解決策ではありません。


1つのオプションは、整数引数を受け入れる operator[]() private オーバーロードを宣言し、それを定義しないことです。

このオプションは、C ++ 11から有効な void operator[](std::nullptr_t) = delete などのオプションとは異なり、すべてのC ++標準(1998以降)で機能します。

operator[]()private メンバーにすると、その式がメンバー関数またはクラスの friend によって使用されない限り、サンプル ohNo[0] で診断可能なエラーが発生します。

その式がメンバー関数またはクラスの friend から使用される場合、コードはコンパイルされますが、関数は定義されていないため、一般にビルドは失敗します(たとえば、未定義の関数によるリンカーエラー)。


std::string(0) が有効な理由は、 0 がNULLポインター定数であるためです。 そのため、ポインターを取るコンストラクターと一致します。 次に、 std::string NULLポインターを渡さないという前提条件に反して実行し std::string 。 リテラル 0 のみがnullポインター定数として解釈されます。intのランタイム値である場合、この問題は発生しません(オーバーロード解決では代わりに int 変換が検索されるため)。 1 はNULLポインター定数ではないため、リテラル 1 も問題ではありません。

コンパイル時の問題(リテラルの無効な値)であるため、コンパイル時にキャッチできます。 このフォームのオーバーロードを追加します。

void operator[](std::nullptr_t) = delete;

std::nullptr_tnullptr のタイプです。 そして、 0ULL 、または nullptr いずれかの NULLポインター定数と一致 ます。 また、関数が削除されるため、オーバーロード解決中にコンパイル時エラーが発生します。







implicit-conversion