Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

boost

Say my code uses std::array, I'd like to do:

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

Such that my project can use std::array without caring about the compiler/platform. One problem (at least) is that when std::array is available, the include will be recursive, when what I really want is (semantically) "include the header that would have been included if this include didn't exist".

Any ideas on how to do this? I know pulling boost::array into std might be considered bad practice as well, so I'm interested about thoughts on that as well.

like image 970
user109078 Avatar asked Oct 20 '14 15:10

user109078


2 Answers

The Right Way to solve this "problem" is to not introduce it in the first place.

If some of your build environments support C++11 but others don't, then find a common subset that is supported under all your build environments and use that. In this case, that common subset appears to be Boost. So you should use boost::array.

Consider also that if you develop & test using std::array, then you have left an entire code branch untested -- the one using boost::array.

I'm all for lazy programming -- but smart lazy programming. Lazy programming doesn't mean hacky or clumsy programming, and smart lazy programming doesn't invoke Undefined Behavior, as adding boost::array to the std namespace would. Saying "I don't want to go through all my code and change std::array to boost::array" isn't a good reason to introduce hacks and undefined behavior. It could be as simple as invoking sed to make all these changes, and it might take you only 5 minutes.

like image 153
John Dibling Avatar answered Oct 01 '22 06:10

John Dibling


You can use the pre-C++11 "template typedef workaround" for this, which does not involve #defining type names, but does make the syntax of using the type a bit uglier:

#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 usage of the type becomes:

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

However, it would be considerably simpler just to use boost::array. It means fewer permutations you have to test and therefore lowers maintenance cost on the codebase.

like image 29
cdhowie Avatar answered Oct 01 '22 06:10

cdhowie