Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

How Can You Check Type Limits in C++? And Create Your Own Limits

2.60/5 (2 votes)
14 Jan 2020MIT4 min read 3.4K  
How to check type limits in C++

In this article, we are going to talk about how to check type limits in C++. This post was inspired by a rule from the first chapter of Code Craft, by Pete Goodliffe, on Defensive programming.

Why Check Type Limits ?

Let’s start by talking about why and when we should check the limit of a type. The first answer that comes to my mind, is because we can. 😝

But there is concrete usage of it. πŸ˜‰

The most common one that I can think about, is when you want to cast a variable from a type to another one. Most of the time, both types will have different limits, so adding an assertion to be sure that the value of the variable is well defined in the destination type, can be a good habit of defensive programming to have.

Another case where you may want to do so, is to avoid undefined behavior, or to use at your advantage the defined behavior of the overflow on some types. So you may want to avoid to have an integer variable overflowing if you increment it too much, since it’s an undefined behavior, but, on the other hand, you may want to have an unsigned variable overflowing on purpose to follow the tic of your CPU when doing embedded programs.

All of those cases involve the limits of the types. And if you have other examples, I would gladly read them in the comments of this article. πŸ˜„

C-style Limits: The Preprocessor Variables

If you have a program on C, or on old C++ (or even new C++ poorly not up to date with the standard), you may have encountered those preprocessor variables storing the limits of the std types.

They look like INT_MIN and INT_MAX, for the integer type, or FLT_MIN and FLT_MAX for the float type. There are also other constants like FLT_EPSILON which represent the difference between 2 float numbers.

You can find the complete list here. Those constants are useful when you need them in C interface, or when coding in C, but if you are using C++, I recommend you to use the next technique. πŸ˜‰

C++ Limits: std::numeric_limits

In the standard C++, there is a class template which provides the limits and some more information of the type of the numerical types of the std. This class is named numeric_limits. If you want, you can find its full documentation here.

It can be used like this:

C++
#include 

constexpr auto int_upper_limit = std::numeric_limits<int>::max();

There are several advantages to this class.

First of all, it provides you a uniform interface for the limits of all the types, which means that it can be used inside a class template, or function, without a problem, while it will be far more difficult with the C style solution.

C++
#include 

template 
class MyClass
{
    void someMethod()
    {
        constexpr auto variable = std::numeric_limits<int>::max();
        // ...
    }
};

Moreover, the syntax is far more clearer that the C style solution, and close to the English language. πŸ€“

Finally, it can be extended to your own types, so that all of the types of your program can use the same interface, and this is what we are going to do now. πŸ˜ƒ

Create Our Own Type Limits

As mentioned in the previous part, a huge advantage of std::numeric_limits is that it can be used with your own types, so that all the types of your program will have the same interface when looking for limits about them. Here is how you can do it for the maximum:

C++
#include 

struct my_type;

template class std::numeric_limits
{
public:
    static constexpr int max() noexcept { return 1; }
};

int main()
{
    constexpr auto my_type_upper_limit = std::numeric_limits<my_type>::max();
    static_assert(my_type_upper_limit == 1, "Error - the limit is not well set");

    return 0;
}

Let’s look into the details of how this example works. πŸ™‚ First, we specify our type, here named my_type, to be able to create a specialization for the class template std::numeric_limits.

In the specialization of the template class, we create a method max which follows the signature defined by the standard. You can, for example, find the prototype of the method max here, and look at the other methods that can be specified in std::numeric_limits here.

Finally, in the main function, we call the method max using std::numeric_limits with our own type. And voilΓ ! Now we have a type which can use the same interface as the standard for its limits! πŸ˜„

Of course, here we have only specified the max method, but you will probably need to specify the min and the lowest methods too. It can be done as we did for the max method. πŸ˜‰

Conclusion

I am not here to start a debate on what is better, C or C++.

If you are using C, then use the C way to check the limits of your types. And if you are using C++, then use the C++ way to do so, it will help you to maintain some consistency in the way you check the types limits in your code.

My point is, if you want to integrate defensive programming (and you should), then, you will need to check the limits of your type, and now, you know how to do it in C++. πŸ˜„

Thank you all for reading this article, And until my next article, have an splendid day! πŸ˜‰

License

This article, along with any associated source code and files, is licensed under The MIT License