Suppose you have this:
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;
}
Is it possible to prevent the implicit conversion?
The only way I could think of is to explicilty provide a constructor that takes an int
and generates some kind of runtime error if the int
is negative, but it would be nicer if I could get a compiler error for this.
I am almost sure, that there is a duplicate, but the closest I could find is this question which rather asks why the implicit conversion is allowed.
I am interested in both, C++11 and pre C++11 solutions, preferably one that would work in both.
Uniform initialization prevents narrowing.
It follows a (not working, as requested) example:
struct Foo {
explicit Foo(unsigned int x) : x(x) {}
unsigned int x;
};
int main() {
Foo f = Foo{-1};
std::cout << f.x << std::endl;
}
Simply get used to using the uniform initialization (Foo{-1}
instead of Foo(-1)
) wherever possible.
EDIT
As an alternative, as requested by the OP in the comments, a solution that works also with C++98 is to declare as private
the constructors getting an int
(long int
, and so on).
No need actually to define them.
Please, note that = delete
would be also a good solution, as suggested in another answer, but that one too is since C++11.
EDIT 2
I'd like to add one more solution, event though it's valid since C++11.
The idea is based on the suggestion of Voo (see the comments of Brian's response for further details), and uses SFINAE on constructor's arguments.
It follows a minimal, working example:
#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
}