In C ++, how to wrap default headers with fallback

Say my code uses std :: array, I would like:

file: array

#pragma once #ifdef MY_TOOLSET_HAS_STD_ARRAY #include <array> //recursive include here? #else #include <boost/array.hpp> namespace std { using boost::array; } #endif 

That way my project can use std :: array without worrying about the compiler / platform. One problem (at least) is that when std :: array is available, include will be recursive when what I really want (semantically) includes a header that would be included if that include did not exist.

Any ideas on how to do this? I know that the attraction of boost :: array in std can be considered bad practice, so I am also interested in thoughts about this.

+5
source share
4 answers

The right way to solve this “problem” is to not introduce it first.

If some of your build environments support C ++ 11 and others do not, then find a common subset that is supported in all build environments and use this. In this case, this common subset seems to be Boost. Therefore you should use boost::array .

Consider also that if you develop and test with std::array , you will leave an entire branch of code unchecked - the one that uses boost::array .

I'm all for lazy programming, but smart lazy programming. Lazy programming does not mean hacking or awkward programming, and intelligent lazy programming does not call Undefined Behavior, since adding boost::array to the std would be. Saying "I do not want to go through all the code and change std::array to boost::array ", this is not a good reason for introducing hacks and Undefined behavior. It can be as simple as calling sed to make all these changes, and it can only take 5 minutes.

+7
source

To do this, you can use pre-C ++ 11 “typedef workaround pattern”, which does not include #defining type names, but makes the syntax for using this type more ugly:

 #ifdef MY_TOOLSET_HAS_STD_ARRAY #include <array> #else #include <boost/array.hpp> #endif template <typename T, size_t N> struct fixed_array { #ifdef MY_TOOLSET_HAS_STD_ARRAY typedef std::array<T, N> type; #else typedef boost::array<T, N> type; #endif }; 

Then your use of the type will be:

 typename fixed_array<char, 4>::type some_chars; 

However, it would be much easier to use boost::array . This means that you need to test fewer permutations and therefore reduce code-based maintenance costs.

+4
source

This is definitely one of those uses of macros:

 // in "my_fixed_array.h" #ifdef MY_TOOLEST_HAS_STD_ARRAY #include <array> #define FIX_ARRAY std::array #else #include <boost/array.hpp> #define FIX_ARRAY boost::array #fi // anywhere else #include "my_fixed_array.h" FIX_ARRAY<char, 4> some_chars; 

This way you don't have to go around doing naughty things, like putting things in namespace std .

+3
source

Depending on how correct the implementation of your compiler is (and most of them are pretty good in this regard), you can simply rely on the order in which to include the path. Typically, the system by default includes paths that are usually looked up before custom "optional" paths are included.

So, if you have a header with the name array , which is in the non-standard include path, you can assume that it will be included only if the standard <array> header is absent, since the first system will be found otherwise. Note that you don’t even need the error detection feature with this technique.

(I did not say that it was beautiful - this is a bit of an abuse of the build environment, although quite safe.)

+1
source

Source: https://habr.com/ru/post/1205107/


All Articles