Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ define a type with allowed values

Tags:

c++

I'm writing a simple class to setup a serial port on an AVR microcontroller. There are some parameters that have only a few meaningful values, for example baud rate, parity type or the number of stop bits. So, I'd like to create a type, a subset of integers, that can either be 1 or 2. I could make an enum type:

enum stopBits { one, two };

I do not like this solution (spelling out baud rate values?). I have come up with this instead:

template<int vv> struct stopBits {
    static_assert( vv == 1 || vv == 2, "stop bit values can be 1 or 2");
    int value = vv;
};
// usage:
stopBits<2> s;

I like this a lot more, and I like having a useful error message from compiler output. I would prefer to be able to instead initialize s with a copy constructor:

// I'd like to have this
stopBits s = 2;

This way, I'd be able to write a class with something like:

serial::serial(baudRate b, stopBits s = 1, parity p = none);

Searching for solutions, I found myself going down a rabbit hole: template parameters deduction, bounded::integer library, function parameters that can not be constexpr, this and this. Can this be done or it is best to surrender and move on? Thanks in advance to everyone.

like image 906
fmiz Avatar asked Jun 03 '26 19:06

fmiz


1 Answers

You can either have run-time or compile-time checks, but not both.

If you have compile-time checks you are forced to somehow hard code the values. This is the domain of constexpr and static_assert. This is somewhat your first solution.

If you want to pass the value into a constructor you are loosing compile time validation, since you are now assigning values and the compiler does not know what value may be passed to the constructor. You can use things like bounded::integer or roll your own that check the value at run-time and behaves accordingly. (e.g. runtime_error)

The question you need to ask yourself what is an immutable property of the code. If it is immutable (for this use case) you should use template arguments. If it is immutable for this instance, but may vary within a use case, you should use a constant member variable.

like image 166
rioki Avatar answered Jun 06 '26 10:06

rioki