あなたがこれを持っているとしましょう:
struct Foo {
Foo(unsigned int x) : x(x) {}
unsigned int x;
};
int main() {
Foo f = Foo(-1); // how to get a compiler error here?
std::cout << f.x << std::endl;
}
暗黙の変換を防ぐことは可能ですか?
私が考えることができる唯一の方法は、int
を受け取り、int
が負の場合に何らかのランタイムエラーを生成するコンストラクターを明示的に提供することですが、このためのコンパイラエラー。
重複があることはほぼ確実ですが、私が見つけた最も近いものは この質問 であり、暗黙の変換が許可される理由を尋ねます。
私はC++ 11とC++ 11以前のソリューションの両方、できれば両方で機能するソリューションに興味があります。
均一な初期化により、絞り込みが防止されます。
これは(要求どおりに機能しない)例に従います。
_struct Foo {
explicit Foo(unsigned int x) : x(x) {}
unsigned int x;
};
int main() {
Foo f = Foo{-1};
std::cout << f.x << std::endl;
}
_
可能な限り、均一な初期化(Foo(-1)
の代わりに_Foo{-1}
_)を使用することに慣れてください。
[〜#〜]編集[〜#〜]
別の方法として、コメントでOPから要求されたように、C++ 98でも機能するソリューションは、コンストラクターがprivate
(_long int
_など)を取得することをint
として宣言することです。
実際にそれらを定義する必要はありません。
別の回答で示唆されているように、_= delete
_も良い解決策になることに注意してください。ただし、これもC++ 11以降のものです。
編集2
C++ 11以降は有効ですが、もう1つソリューション、イベントを追加したいと思います。
このアイデアはVooの提案に基づいており(詳細については、Brianの応答のコメントを参照)、コンストラクターの引数にSFINAEを使用しています。
これは、最小限の実用的な例に従います。
_#include<type_traits>
struct S {
template<class T, typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
S(T t) { }
};
int main() {
S s1{42u};
// S s2{42}; // this doesn't work
// S s3{-1}; // this doesn't work
}
_
不要なオーバーロードを削除することで、コンパイルエラーを強制できます。
Foo(int x) = delete;
everyこのようなコードの発生について警告が必要で、GCCを使用している場合は、-Wsign-conversion
オプションを使用してください。
foo.cc: In function ‘int main()’:
foo.cc:8:19: warning: negative integer implicitly converted to unsigned type [-Wsign-conversion]
Foo f = Foo(-1); // how to get a compiler error here?
^
エラーが必要な場合は、-Werror=sign-conversion
を使用してください。