C++: How to avoid implicit conversions

Epitome of a C++ exception. Jester Box.

Godbolt updated.

Release 0.6.0

For Visual Studio users pompously named epiphany.h is added. Idea is to turn some quiet implicit conversion warnings into errors.  Just enough to make your code not compilable without the help of  nothing_but<T>. Also data() method and assignment methods got their ref. qualified variants. In order to stop taking data from temporary objects and to stop assigning to temporary objects.

Release 0.5.0

GitHub: Value Handle to Avoid Implicit Conversions in standard C++. This is the official and latest version: “0.5.0”. The major change is, “0.5.0” and tests over there, are made for runtimes where this utility will be most likely used. That means no exceptions, no RTTI, no streams. Please use that code and tests as a reference.

Motivation

Probably you indulge in recreational C++ and the following is just a curiosity for you:

Or you do take the above so seriously you actually do not use C++ on a mission-critical project? Perhaps inside some medical equipment, your company has to deliver?

You might take the C++ implicit conversions so seriously that “even” the following is a very serious matter for you.

Not because you happen to be “unreasonable”, but because you need to deliver code where implicit conversion is 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.

And very likely, you have turned to the “official sources” just to come back disappointed.

One option is to plan for the usual extended test/debug/test/debug … ad infinitum cycling, of course.

The suggestion

Before you discard C++ (with the heavy heart)  for mission-critical projects completely, we might suggest you look into this ridiculously tiny single header? Here is some code to tickle your fancy.

Declarations first. As ever, this makes the default initialized content, but with a twist: of exactly the types required.

Usage? That is the interesting part. To actually assign anything to these types you must very consciously make those types first. The act of assignment is not transparent. Thus assignment does not hide the implicit conversion.

You or your team simply can not introduce a bug there. The following will simply not compile.

Just a perfect API to avoid those nasty little pests growing into bugs very difficult to find. And software where implicit conversions are a problem definitely can not afford those bugs. Or any bugs.

Great, is that it? Are we done here yet? No, it is not it. And we are not done here yet. There is more.

In case you might think the only simple implicit conversion of fundamental types, can be targeted with this API, how about something a bit more involved?

Non-Trivial Use-Case

Let’s assume your C++, for the heart monitor module at one point needs exactly an array of 3 integers. Aka int three_ints[3] = {1,2,3};
But. Not a “naturally decayed” pointer and not unsigned int type of those elements, but exactly as the MISRA based requirement requested: an array of three integers, and nothing else but an array of three integers.

Now, I am sure if really pressed you can devise some clever C++, ad-hoc solution. Provided you are allowed to use them “clever solutions” in your heart monitoring device module. Which I am sure you are definitely not. Ugh.

Alternatively, perhaps we can interest you in the following snippet?

Please remember the elements of that vector are instances of nothing_but<T>, thus you need to use the data method to get to the values.

Now, this might seem like a “not a lot of code” to you, but we are just showing an API new to you. It can be used in a much more condensed manner.

The 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 this time and here, with this API.

Type’s handled

We do handle all the arithmetic types.

Those are the types where implicit conversions do happen, by default. But what about compound types? For example:

Why not handle them too? Simply because in case you need them you will naturally use them as ever before, made up of fundamental types, and combined with this API.

Please do note, how above, all the standard C++ default value initialization rules are respected. In case of some serious bugs, singularities discovered, or edge cases, we will reconsider the currently handled types. Going beyond arithmetics it is very unlikely the implicit conversion might be the problem.

Dependencies

  • This API depends on C++ std lib only.
  • We are developing using the Visual Studio 2017 15.9.X,
    • using clang-cl.exe aka “clang 10.0.0”
  • We are always checking is it equally usable with both CLANG and GCC, by using Godbolt

Installation

This API is header-only: it consists entirely of one header file:

dbj_nothing_but.h , repository: https://github.com/dbj-systems/nothingbut

Thus it is perfectly usable in your Godbolt experiments as it is in that link above.

No compilation is necessary. No installation is required.

Just make it part of your project. Every attempt has been made to make this into a cross-platform,
header only, standard C++ library.

License

Copy-paste away.

Contact

Please report issues or questions here.
You can contact me via Twitter at @dbjdbj, or via dbj at dbj dot org.

Contributing

Any feedback from users and stakeholders will be reviewed and might be used to improve the library.


 

So little C++ so much good!
So little C++ so much good!