Home | Libraries | People | FAQ | More |
The default algorithm employed by CXXD to choose whether to use a Boost library or its C++ standard equivalent for any mod is very simple. If the C++ standard library is available during compilation it is chosen and if it is not available during compilation its equivalent Boost library is chosen.
The determination of availability for any given mod is done by examining Boost Config macros. Boost Config has quite a number of macros which will specify which C++ standard library is available during compilation. The logic of determining which library is available is determined within Boost Config, and CXXD just uses the results of that logic to configure the macros for a particular mod.
The logic of setting the macros for any particular mod occurs when the mod implementation header for that mod is included in the code. Each mod header automatically includes its corresponding mod implementation header, so the programmer need only include the mod header to cause the choice to be made. The logic is completely preprocessor macro based, and is specific to each mod implemenattion header, although the logic for each mod implementation header is generally the same.
As an example, using the regex mod:
#include <boost/cxx_dual/regex.hpp> ... code
If Boost Config determines that the C++ standard regex library is available CXXD_HAS_STD_REGEX is defined as '1', CXXD_REGEX_NS is defined as 'std', and CXXD_REGEX_HEADER is defined as '<regex>'. If Boost Config determines that the C++ standard regex library is not available CXXD_HAS_STD_REGEX is defined as '0', CXXD_REGEX_NS is defined as 'boost', and CXXD_REGEX_HEADER is defined as '<boost/regex.hpp>'.
Although CXXD chooses automatically whether the Boost library or the C++ standard library is to be used for any given mod the programmer may decide to override this choice. The method of overriding the choice is to define a particular macro before including a particular mod header.
The programmer may override the automatic choice of CXXD by specifying that the Boost library be used or by specifying that the C++ standard library be used. If the programmer specifies that the C++ standard library be used and that library is not available for use, a preprocessor error will normally be generated.
While it may seem reasonable that the programmer can override the choice by specifying that the Boost library be chosen for a particular mod, it might seem odd that programmer should be able to override the choice by specifying that the C++ standard library be chosen for a particular mod, considering the fact that the default choosing algorithm will automatically choose the C++ standard library if it is available. Specific cases for allowing this will be discussed later in the documentation, but the general case is that it is possible that a programmer, when using a particular mod, wants to makes sure that the C++ standard library is available. else he wants to force a preprocessing error.
For any given mod 'XXX' defining a macro called CXXD_'XXX'_USE_BOOST specifies that the Boost library will be used. If used CXXD_'XXX'_USE_BOOST must always be defined to expand to nothing, as in:
#define CXXD_'XXX'_USE_BOOST
where XXX is the uppercase name of the mod.
For any given mod 'XXX' defining a macro called CXXD_'XXX'_USE_STD specifies that the C++ standard library will be used. If used CXXD_'XXX'_USE_STD must always be defined to nothing, as in:
#define CXXD_'XXX'_USE_STD
where XXX is the uppercase name of the mod.
The specific override macros for each mod are:
Table 1.6. Specific override macros
Mod |
Boost override macro |
C++ standard override macro |
---|---|---|
array |
CXXD_ARRAY_USE_BOOST |
CXXD_ARRAY_USE_STD |
atomic |
CXXD_ATOMIC_USE_BOOST |
CXXD_ATOMIC_USE_STD |
bind |
CXXD_BIND_USE_BOOST |
CXXD_BIND_USE_STD |
chrono |
CXXD_CHRONO_USE_BOOST |
CXXD_CHRONO_USE_STD |
condition_variable |
CXXD_CONDITION_VARIABLE_USE_BOOST |
CXXD_CONDITION_VARIABLE_USE_STD |
enable_shared_from_this |
CXXD_ENABLE_SHARED_FROM_THIS_USE_BOOST |
CXXD_ENABLE_SHARED_FROM_THIS_USE_STD |
function |
CXXD_FUNCTION_USE_BOOST |
CXXD_FUNCTION_USE_STD |
hash |
CXXD_HASH_USE_BOOST |
CXXD_HASH_USE_STD |
make_shared |
CXXD_MAKE_SHARED_USE_BOOST |
CXXD_MAKE_SHARED_USE_STD |
mem_fn |
CXXD_MEM_FN_USE_BOOST |
CXXD_MEM_FN_USE_STD |
move |
CXXD_MOVE_USE_BOOST |
CXXD_MOVE_USE_STD |
mutex |
CXXD_MUTEX_USE_BOOST |
CXXD_MUTEX_USE_STD |
random |
CXXD_RANDOM_USE_BOOST |
CXXD_RANDOM_USE_STD |
ratio |
CXXD_RATIO_USE_BOOST |
CXXD_RATIO_USE_STD |
ref |
CXXD_REF_USE_BOOST |
CXXD_REF_USE_STD |
regex |
CXXD_REGEX_USE_BOOST |
CXXD_REGEX_USE_STD |
shared_mutex |
CXXD_SHARED_MUTEX_USE_BOOST |
CXXD_SHARED_MUTEX_USE_STD |
shared_ptr |
CXXD_SHARED_PTR_USE_BOOST |
CXXD_SHARED_PTR_USE_STD |
system_error |
CXXD_SYSTEM_ERROR_USE_BOOST |
CXXD_SYSTEM_ERROR_USE_STD |
thread |
CXXD_THREAD_USE_BOOST |
CXXD_THREAD_USE_STD |
tuple |
CXXD_TUPLE_USE_BOOST |
CXXD_TUPLE_USE_STD |
type_index |
CXXD_TYPE_INDEX_USE_BOOST |
CXXD_TYPE_INDEX_USE_STD |
type_traits |
CXXD_TYPE_TRAITS_USE_BOOST |
CXXD_TYPE_TRAITS_USE_STD |
unordered_map |
CXXD_UNORDERED_MAP_USE_BOOST |
CXXD_UNORDERED_MAP_USE_STD |
unordered_multimap |
CXXD_UNORDERED_MULTIMAP_USE_BOOST |
CXXD_UNORDERED_MULTIMAP_USE_STD |
unordered_multiset |
CXXD_UNORDERED_MULTISET_USE_BOOST |
CXXD_UNORDERED_MULTISET_USE_STD |
unordered_set |
CXXD_UNORDERED_SET_USE_BOOST |
CXXD_UNORDERED_SET_USE_STD |
weak_ptr |
CXXD_WEAK_PTR_USE_BOOST |
CXXD_WEAK_PTR_USE_STD |
If for any given mod 'XXX' both CXXD_'XXX'_USE_BOOST and CXXD_'XXX'_USE_STD is defined a preprocessing error will occur when the mod header for 'XXX' is included.
As examples, using the regex mod:
#define CXXD_REGEX_USE_BOOST #include <boost/cxx_dual/regex.hpp> ... code
CXXD_HAS_STD_REGEX is defined as '0', CXXD_REGEX_NS is defined as 'boost', and CXXD_REGEX_HEADER is defined as '<boost/regex.hpp>'.
#define CXXD_REGEX_USE_STD #include <boost/cxx_dual/regex.hpp> ... code
CXXD_HAS_STD_REGEX is defined as '1', CXXD_REGEX_NS is defined as 'std', and CXXD_REGEX_HEADER is defined as '<regex>', as long as the C++ standard regex library is available for use, else a preprocessing error is generated.
Along with the specific macros of the form CXXD_'XXX'_USE_BOOST and CXXD_'XXX'_USE_STD which override default processing for the specific 'xxx' mod the programmer can specify either of two generalized macros which overrides default processing for any mod.
Defining a macro called CXXD_USE_BOOST specifies that the Boost library will be used for any mod. If used CXXD_USE_BOOST must always be defined to nothing, as in:
#define CXXD_USE_BOOST
Defining a macro called CXXD_USE_STD specifies that the C++ standard library will be used for any mod. If used CXXD_USE_STD must always be defined to nothing, as in:
#define CXXD_USE_STD
If both CXXD_USE_BOOST and CXXD_USE_STD is defined a preprocessing error will occur when any mod header is included.
If for any given mod 'xxx' both CXXD_'XXX'_USE_BOOST and CXXD_USE_STD is defined a preprocessing error will occur when the mod header file for 'xxx' is included.
If for any given mod 'xxx' both CXXD_'XXX'_USE_STD and CXXD_USE_BOOST is defined a preprocessing error will occur when the mod header file for 'xxx' is included.
As examples, using the regex mod:
#define CXXD_USE_BOOST #include <boost/cxx_dual/regex.hpp> ... code
CXXD_HAS_STD_REGEX is defined as '0', CXXD_REGEX_NS is defined as 'boost', and CXXD_REGEX_HEADER is defined as '<boost/regex.hpp>'.
#define CXXD_USE_STD #include <boost/cxx_dual/regex.hpp> ... code
CXXD_HAS_STD_REGEX is defined as '1', CXXD_REGEX_NS is defined as 'std', and CXXD_REGEX_HEADER is defined as '<regex>'. as long as the C++ standard regex library is available for use, else a preprocessing error is generated.
#define CXXD_REGEX_USE_BOOST #define CXXD_USE_STD #include <boost/cxx_dual/regex.hpp> ... code
A preprocessing error is generated.
#define CXXD_REGEX_USE_STD #define CXXD_USE_BOOST #include <boost/cxx_dual/regex.hpp> ... code
A preprocessing error is generated.
Using any CXXD mod header:
#define CXXD_USE_BOOST #define CXXD_USE_STD #include <boost/cxx_dual/'any_cxxd_mod_header' ... code
A preprocessing error is generated.
The purpose of using overriding macros, for any mod with the specific overriding macros or for CXXD as a whole with the general overriding macros, is to override the default algorithm which CXXD uses to choose a dual library. However using overriding macros for one's own direct use(s) of CXXD is generally foolish. This is because the easiest implementation, rather than using an overriding macro, is to just to not use CXXD for a mod in favor of using either the Boost library or C++ standard library directly.
In other words, instead of:
#define CXXD_USE_BOOST #include <boost/cxx_dual/regex.hpp> cxxd_regex_ns::regex my_regex; // etc. ... code
you can simply code:
#include <boost/regex.hpp> boost::regex my_regex; // etc. ... code
and instead of:
#define CXXD_USE_STD #include <boost/cxx_dual/regex.hpp> cxxd_regex_ns::regex my_regex; // etc. ... code
you can simply code:
#include <regex> std::regex my_regex; // etc. ... code
In this sense the examples given above of using specific or general overriding macros are purely artificial in order to merely show what the meaning of these overriding macros entail. In actual code directly overriding a particular mod should almost never be done in favor of directly using either the Boost or C++ standard implementations of a dual library.
So what is the actual purpose of the overriding macros ? The purpose is to override the use of CXXD by another library whose source files can not or should not be modified. A third-party library may choose to use CXXD to provide a dual library for a particular mod. Your own code, which uses the third-party library but otherwise uses either the Boost version of the dual library or the C++ standard version of the dual library in all other situations, may enforce its own usage on the dual library interface of the third-party library by using an overriding macro. As an example a third-party library might have as a public interface:
// Header file ThirdPartyHeader.hpp #include <boost/cxx_dual/regex.hpp> class ThirdPartyClass { public: void SomeFunction(cxxd_regex_ns::regex &); ... // other functionality };
We will assume, in this instance, this is a header-only library ( an extended discussion of using CXXD with a non-header-only library will follow later in the documentation ). In one's own code you may desire to use the ThirdPartyClass::SomeFunction interface with specifically the Boost regex library only. Your own code might then look like:
#define CXXD_REGEX_USE_BOOST #include <ThirdPartyHeader.hpp> boost::regex my_regex("SomeRegularExpression etc."); ThirdPartyClass tpclass; tpclass.SomeFunction(my_regex);
Conversely you may decide that your use of the ThirdPartyClass::SomeFunction interface should be with the C++ standard regex library only, so your code might then look like:
#define CXXD_REGEX_USE_STD #include <ThirdPartyHeader.hpp> std::regex my_regex("SomeRegularExpression etc."); ThirdPartyClass tpclass; tpclass.SomeFunction(my_regex);
Instead if you did accept the dual nature of the ThirdPartyHeader.hpp header, your code might then like:
#include <ThirdPartyHeader.hpp> cxxd_regex_ns::regex my_regex("SomeRegularExpression etc."); ThirdPartyClass tpclass; tpclass.SomeFunction(my_regex);
In other words using the overriding macros of CXXD serves the purpose of using some already established interface involving CXXD without changing that interface's own code, at the same time forcing the choice of a particular dual library to be used. We can say that overriding macros change the dual library nature of a mod to a single library interface.
There is a situation where the programmer may choose to override his own use of a particular mod. This is when he programs his own interface using a particular mod but decides for a particular combination of compiler and/or OS that he wants to override that choice. In other words the programmer wishes to use a dual library for the benefits that CXXD has to offer but knows that for some combination of compiler and/or operating system that the particular dual library choice must be overridden for a reason, perhaps to prevent a faulty library implementation from being used.
Let's imagine that for a particular compiler version 'CCC' version 'NNN' on a particular OS 'OOO' we know that the standard library version of mod 'XXX' is buggy. Also let's imagine that we can test for the buggy combination through using the preprocessor defines, as we can do in Boost through either Boost.Config or even more easily through Boost.Predef. Our pseudocode for overriding our own use of the dual library in a header file might look like:
// Header file OwnOverrideHeader.hpp #if CCCNNN && OOO #define CXXD_XXX_USE_BOOST #endif #include <boost/cxx_dual/XXX.hpp> class OwnOverrideClass { public: void SomeOwnOverrideFunction(cxxd_xxx_ns::xxx_object &); ... // other functionality };
So essentially where the purpose of the override macros is to change another interface's dual library choice for a particular mod to a single library, you can use the override macros with one's own interface in order to provide one-off situations where you want to specifically control the library chosen for a mod for a particular compiling environment.