次の 2 つのアプローチが思い浮かびます。
「署名済み」タイプの明示的な変換を追加します。
#include <cassert>
class A {
unsigned int x;
public:
A(unsigned int X) : x(X) {}
explicit A(int X) : x(static_cast<unsigned>(X)) {
assert(X>=0); // note X, not x!
}
};
int main()
{
A ok(5);
A bad(-5);
}
より適切なオーバーロードを削除して、暗黙的な変換を禁止します。
A(int X) = delete;
A(long X) = delete;
A(char X) = delete;
これにより、すべてのユーザーは、A インスタンスを構築する前に unsigned にキャストする必要があります。安全ですが、不器用です。
これはすべての整数型 ( s など)からの暗黙的な変換を禁止するわけではないので、これをばかにするためにさらに多くのことを行う必要があることに注意してください。enum
以下は、符号付きの値が含まれる場合を除き、すべての暗黙的な変換を受け入れる基本的な SFINAE ベースの例です。
#include <type_traits>
#include <limits>
class A {
unsigned int x;
public:
template<typename T, typename = typename std::enable_if<std::is_integral<T>::value, void>::type>
A(T X) : x(X)
{
static_assert(!std::numeric_limits<T>::is_signed, "Signed types cannot be accepted");
}
};
int main()
{
A ok(5u);
A bad(-5);
}