Boost logo

Boost :

From: Edward Diener (eldiener_at_[hidden])
Date: 2020-12-02 00:17:15


On 12/1/2020 6:39 PM, Gavin Lambert via Boost wrote:
> 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 <boost/array.hpp>
>>> #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 <boost/cxx_dual/array.hpp>
>> #define mixmaxarray cxxd_array_ns::array
>
> You shouldn't use #define for that sort of thing anyway.  Define a local
> typedef:

I only used #define to mimic the original example. You are correct that
a typedef or type alias is the right way. In cxx_dual 'cxxd_array'
becomes the correct namespace, rather than 'std' or 'boost' and the
programmer can go from there.

>
> 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*.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk