I have a code in which user has to pass > 0 number otherwise this code will throw. Using type of this arg as std::size_t doesn't work for the reason that negative numbers give large positive numbers. Is it good practice if I use signed type or are there other ways to enforce it?
void f(std::size_t number)
{
//if -1 is passed I'm (for obvious reason) get large positive number
}
I don't think there's a definitive correct answer to this question. You can take an look to Scott Meyers's opinion on the subject :
One problem is that unsigned types tend to decrease your ability to detect common programming errors. Another is that they often increase the likelihood that clients of your classes will use the classes incorrectly.
In the end, the question to ask is really : do you need the extra possible values provided by the unsigned type ?
A lot depends on what type of argument you imagine your clients trying to pass. If they're passing int, and that's clearly big enough to hold the range of values you're going to use, then there's no practical advantage to using std::size_t - it won't enforce anything, and the way the issue manifests as an apparently huge number is simply more confusing.
BUT - it is good to use size_t anyway as it helps document the expectations of the API.
You clearly can't do a compile-time check for "> 0" against a run-time generated value, but can at least disambiguate negative inputs from intentional huge numbers ala
template <typename T>
void f(T t)
{
if (!(t > 0))
throw std::runtime_error("be positive!");
// do stuff with t, knowing it's not -1 shoehorned into size_t...
...
}
But, if you are really concerned about this, you could provide overloads:
// call me please e.g. f(size_t(10));
void f(size_t);
// unimplemented (and private if possible)...
// "want to make sure you realise this is unsigned: call f(size_t) explicitly
void f(int32_t);
void f(int64_t);
...then there's a compile-time error leading to the comments re caller explicitly providing a size_t argument (casting if necessary). Forcing the client to provide an arg of size_t type is a pretty good way to make sure they're conscious of the issue.
Rin's got a good idea too - would work really well where it works at all (depends on there being an signed int type larger than size_t). Go check it out....
EDIT - demonstration of template idea above...
#include <iostream>
template <typename T>
void f(T t)
{
if (!(t > 0))
std::cout << "bad call f(" << (int)t << ")\n";
else
std::cout << "good f(" << (int)t << ")\n";
}
int main()
{
f((char)-1);
f((unsigned char)255);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With