Как предотвратить неявное преобразование из int в unsigned int?
Предположим, что у вас есть это:
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 и pre C++11, предпочтительно тот, который будет работать в обоих.
3 ответа:
Равномерная инициализация предотвращает сужение.
Он следует примеру (не работает, как и было предложено):
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)
) везде, где это возможно.EDIT
В качестве альтернативы, согласно запросу OP в комментариях, решение, которое работает также с C++98, должно объявить как
private
конструкторы, получающиеint
(long int
, и так далее).
На самом деле нет необходимости их определять.
Замечание это= delete
было бы также хорошим решением, как предложено в другом ответе, но это тоже начиная с C++11.EDIT 2
Я хотел бы добавить еще одно решение, хотя оно действительно с C++11.
Идея основана на предложении Voo (смотрите комментарии ответа Брайана для более подробной информации) и использует 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 }
Если вы хотите, чтобы вас предупреждали о каждом появлении такого кода, и вы используете 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
.