On 2/12/2020 11:01 am, Edward Diener wrote:
On 12/1/2020 4:36 PM, Kostas Savvidis wrote:
#ifndef BOOST_NO_CXX11_HDR_ARRAY #include <array> #define mixmaxarray std::array #else #include
#define mixmaxarray boost::array #endif ...#undef mixmaxarray The other alternative kindly proposed by Steven was: namespace boost { namespace random { namespace arrayns = std; } }
I wrote a library called cxx_dual ( https://github.com/eldiener/cxx_dual ) to solve a problem like yours, but it did not meet with general approval. With cxx_dual your code above could have been:
#include
#define mixmaxarray cxxd_array_ns::array
You shouldn't use #define for that sort of thing anyway. Define a local typedef: namespace boost { namespace mylib { typedef cxxd_array_ns::array mixmaxarray; } } (Or a "using" alias, if you can assume C++11.) However this is only actually correct behaviour if it's a header-only library. In a compiled library, what you actually should do is something closer to this: // header file #if SOME_CONDITION typedef std::foo myfoo; namespace detail1 { class aclass { ...; std::foo m_foo; }; } typedef detail1::aclass aclass; #else typedef boost::foo myfoo; namespace detail2 { class aclass { ...; boost::foo m_foo; }; } typedef detail2::aclass aclass; #endif class commonclass { void method(myfoo const& x); }; // cpp file 1 #if CAN_COMPILE_STD_FOO // or equivalently set build rules to skip this file if std::foo doesn't // exist at build time void commonclass::method(std::foo const& x) { ... } // implementation for detail1::aclass #endif // cpp file 2 void commonclass::method(boost::foo const& x) { ... } // implementation for detail2::aclass Note that the condition used to select the implementation in the header file is not necessarily the same as the one used to decide whether to build the std implementation (the first may be influenced by a user preference, the second is not). Also note that the two implementations are in separate cpp files because linkers have an easier time throwing away entire object files if they're not referenced (at least in static libraries), and may be less good at doing that for individual symbols. And you *don't* make building the second file conditional. If these rules are followed, and as long as the library is compiled with the highest-desired-C++-standard, this allows apps to link against it using either class safely -- you can even have a mix of both in the same app provided those components don't try to directly talk to each other. Actually doing these things in any non-trivial library, however, is *very hard* -- not impossible, if you leverage some preprocessor tricks -- but it's not surprising that most people don't want to do it until they have no other choice. There's also a lot of subtle complications where the compiler doesn't especially help you to catch violations, for things even as simple as private members; pimpl helps but it's still tricky, and has performance tradeoffs. ("aclass" avoids those problems but introduces some of its own.) And it quickly snowballs (as you add more dependencies) into an unmanageable mess, unless you can take a whole slate of dependencies as a fixed unit rather than having them individually configurable. (It's perhaps worth noting that this doesn't *only* apply to compiled libraries; this is similar to how glibc handles the different implementations of std::string between C++03 and C++11, for example.) C++ ABI is *hard*.