“… C++ is not a bad language per se. It’s just, well kinda suffers from bloat. In the words of Richard E. Gooch, “It seduces the programmer, making it much easier to write bloatware“…”
Probably you indulge into recreational C++ and the following is (perhaps), just a curiosity for you:
// these are MSVC typedef's
typedef unsigned char uint8_t;
typedef signed char int8_t;
// CLANG/GNUC/G++/MSVC/UCRT default
// behaviour is :
// no warnings whatsoever here
// signed to unsigned ?
char uint8_t uc = int8_t('s');/
// unsigned to signed ?
char int8_t sc = uc;
Or perhaps you are not fan of “recreational programming” and you do take the above so seriously you actually do not use C++ on mission critical projects? Perhaps your code has to be installed, inside some medical equipment your company delivers?
You might take the C++ implicit conversions so seriously that “even” the following is a very serious matter for you.
// implicit conversion of int to char
char C = 64 ;
// implicit conversion of double to float
float F = 3.7;
Not because you happen to be “unreasonable”, but because you need to deliver code where implicit conversion are simply not allowed. Just like for example exceptions, in many real-time projects are not allowed. They simply do not exist over there. Simply switched off.
Here is yet another (not that) funny example:
int i = -1;
unsigned int j = 1;
if ( i < j )
std::cout << " i is less than j";
std::cout << " i is greater than j";
i is greater than j
Not laughing any more. And very likely, you have already turned to the “official sources” just to come back disappointed. Those advice are, to put it mildly, not feasible, in real life, non-trivial projects.
Interestingly, some other coding platforms, do have exact types , should we say “for ages”. Alas, never part of C++ or C.
One options is to plan for usual extended test/debug/test/debug, cycles ad-infinitum, of course. Spending a **lot** of time chasing this kind of bugs.
Before you dump C++, can we offer to you
So, before you start learning Ada and discard (with the heavy heart) C++ for your mission critical projects, we might perhaps suggest you look into this ridiculously tiny single standard C++ header? Here is some code to tickle your fancy.
// let's assume your code must not accidentally mix
// signed and unsigned chars
= dbj::util::nothing_but<signed char>
= dbj::util::nothing_but<unsigned char>
Just declarations first. As ever, make default initialized content, but with a twist: of exactly the types required.
// signed char 0
// unsigned char 0
Now comes the interesting part.
To actually assign anything to these types you must very consciously make those types first.
// using MSVC typedefs here
// and C++ style cast
s = int8_t('s');
u = uint8_t('u');
You, or your team simply can not introduce a bug there. The following will simply not compile.
s = 's'; // does not compile
u = 'u'; // does not compile
s = u; // does not compile
s == u; // does not compile
Just a perfect API to avoid those nasty little pests growing into bugs very difficult to find.
Now, this might seem like “not a lot of code” to you, but we are just showing an API new to you. Above code looks almost too simple. It is easy to forget the safety service this API provides.
Now the really worn out phrase: Your imagination is the limit. Very true here.
This API does handle all the arithmetic types.
- integral types
- signed char
- short int
- long int
- long long int
- unsigned char
- unsigned short int
- unsigned int
- unsigned long int
- unsigned long long int
- floating point types
- long double
These are the types where implicit conversions do happen, by design.
But what about compound types? For example what about:
Why not handling them too? Simply because, in case you need them you will naturally use them as ever before, but combined with this API.
// 0 of a signed char type
just_signed signed_char ;
// pointer to it
just_signed * signed_char_pointer ; // null_ptr as ever_
// reference to it
just_signed & signed_char_ref = signed_char ;
// array of three elements of it
Please do note, how above, all the standard C++ default value initialization rules are respected.
In case of some serious bugs, or singularities discovered, or edge case, we will reconsider the currently handled types.
Going beyond arithmetics it is very unlikely the implicit conversion might be the problem in your code.
This API depends on C++ std lib only. We are developing using the Visual Studio 2017 15.9.X, But we are always checking it is equally usable with both CLANG and GCC.
This API is header-only: it consists entirely of one header file:
No compilation necessary. No installation required.
Just drop it in and include. Make it part of your project.
Every attempt has been made to make this into a cross-platform, header only, standard C++ library.
At time of this writing (2019-Q1) standard C++ is C++17.
- Builds and tests are passing with C++14 (/std:c++14)
- Builds and tests are passing with C++17 (/std:c++17)
This is open source software. Distributed under the GPLv3 License, Version 1.0.
Please report issues or questions here.
You can contact me via twitter at @dbjdbj
Any feedback from users and stakeholders will be used to improve the library.
Value Handle to Avoid Implicit Conversions in standard C++
Copyright(C) 2019 Dušan B. Jovanović (firstname.lastname@example.org)
This program is free software : you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see https://www.gnu.org/licenses/.