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