Home | Libraries | People | FAQ | More |
The basic functionality of the CXXD library has been explained and should serve most programmers when using the library without having to know anything further about CXXD. The basic functionality involves including a single header file for a given mod and then using the namespace alias to program the functionality which the mod provides, with the same syntax being used no matter which library has been chosen. This functionality, along with occasional use of macros which CXXD provides for each mod, is the mainstream way of programming CXXD.
This method of programming does not necessarily change when the programmer uses the advanced functionality of CXXD, which will now be explained. Instead the advanced functionality offers further methods to help the programmer when using a dual library. The advanced functionality entails:
When you include a mod header in a TU you are actually including a separate implementation header file and then using the macros in that implementation header file to do two things:
All of the logic of choosing the dual library and of creating macros reflecting that choice is done in the low-level implementation header file. The implementation header file for each mod is in the CXXD 'boost/cxx_dual/impl' subdirectory and has the same name as its corresponding mod header in the 'boost/cxx_dual' directory.
Both the 'shared_ptr.hpp' and 'shared_ptr_all.hpp' mod headers for the shared_ptr mod use the same implementation header called 'shared_ptr.hpp'.
All of the macros, except one, which could be used by the programmer when including a mod header have been explained as aids to using the basic functionality of CXXD. The one macro which was not explained, because it does not directly impact the basic functionality, is a macro which is used to include the C++ header file(s) needed by the dual library which has been chosen. The form of this macro is CXXD_'XXX'_HEADER for any given mod XXX:
Table 1.5. C++ header macros
Mod name |
C++ header macro |
---|---|
array |
CXXD_ARRAY_HEADER |
atomic |
CXXD_ATOMIC_HEADER |
bind |
CXXD_BIND_HEADER |
chrono |
CXXD_CHRONO_HEADER |
condition_variable |
CXXD_CONDITION_VARIABLE_HEADER |
enable_shared_from_this |
CXXD_ENABLE_SHARED_FROM_THIS_HEADER |
function |
CXXD_FUNCTION_HEADER |
hash |
CXXD_HASH_HEADER |
make_shared |
CXXD_MAKE_SHARED_HEADER |
mem_fn |
CXXD_MEM_FN_HEADER |
move |
CXXD_MOVE_HEADER |
mutex |
CXXD_MUTEX_HEADER |
random |
CXXD_RANDOM_HEADER |
ratio |
CXXD_RATIO_HEADER |
ref |
CXXD_REF_HEADER |
regex |
CXXD_REGEX_HEADER |
shared_mutex |
CXXD_SHARED_MUTEX_HEADER |
shared_ptr |
CXXD_SHARED_PTR_HEADER |
system_error |
CXXD_SYSTEM_ERROR_HEADER |
thread |
CXXD_THREAD_HEADER |
tuple |
CXXD_TUPLE_HEADER |
type_index |
CXXD_TYPE_INDEX_HEADER |
type_traits |
CXXD_TYPE_TRAITS_HEADER |
unordered_map |
CXXD_UNORDERED_MAP_HEADER |
unordered_multimap |
CXXD_UNORDERED_MULTIMAP_HEADER |
unordered_multiset |
CXXD_UNORDERED_MULTISET_HEADER |
unordered_set |
CXXD_UNORDERED_SET_HEADER |
weak_ptr |
CXXD_WEAK_PTR_HEADER |
For all mods this C++ header macro expands to the include path of a header file using the angle bracket form ( '<' and '>' ). For a few mods this C++ header macro actually expands to a header file in the CXXD implementation detail directory, which itself includes more than one library header file. For the rest this C++ header macro expands to a single C++ header for either the Boost or C++ standard library dual library, which itself includes all constructs needed by the dual library chosen.
The shared_ptr mod implementation header also has a separate C++ header macro called 'CXXD_SHARED_PTR_ALL_HEADER'. This C++ header macro is used by the 'shared_ptr_all.hpp' mod header to include the C++ header files needed by shared_ptr, weak_ptr, make_shared, and enable_shared_from_this for either the Boost dual library or the C++ standard dual library chosen.
Because of the C++ header macro, and because the previously discussed namespace macro can be used anytime the namespace alias can be used, it is possible to forgo the inclusion of the mod header and use the low-level inclusion of the same-named implementation header file for any given mod. As an example, when using the regex mod the code showing basic functionality of CXXD was:
#include <boost/cxx_dual/regex.hpp> void SomeFunction() { cxxd_regex_ns::regex re("A regular expression etc."); bool result(cxxd_regex_ns::regex_match("Some string...",re)); // etc. }
Alternatively using the low-level implementation header the code could be:
#include <boost/cxx_dual/impl/regex.hpp> #include CXXD_REGEX_HEADER void SomeFunction() { CXXD_REGEX_NS::regex re("A regular expression etc."); bool result(CXXD_REGEX_NS::regex_match("Some string...",re)); // etc. }
or even:
#include <boost/cxx_dual/impl/regex.hpp> #include CXXD_REGEX_HEADER namespace cxxd_regex_ns = CXXD_REGEX_NS; void SomeFunction() { cxxd_regex_ns::regex re("A regular expression etc."); bool result(cxxd_regex_ns::regex_match("Some string...",re)); // etc. }
Once you include a mod header in a TU there is no point in separately including the low-level mod implementation header, since the mod header already does so. However separately including both the mod header and low-level mod implementation for a particular mod does no harm, no matter what order they are included or how many times they are included.
Obviously using the low-level implementation header is more verbose as can be seen in previous examples. So why would we ever want to use it as opposed to the normal mod header ?
Including the low-level implementation header, rather than the mod header, gives the programmer specific control over which header file(s) get included for the dual library chosen and how the constructs in the dual library chosen are referred to. When including the mod header that choice is automatically made by including the most general header file(s) needed and by creating a namespace alias for referring to the top-level constructs of a dual library. Including the low-level implementation header allows the programmer to manually make such choices.
Furthermore, unlike including a mod header, including the low-level header for a mod does not create any immediate dependency on the dual library chosen. This is particularly relevant if you want to use the mod's choosing macro to write one-off code which does not use CXXD's dual library support at all.
Many programmers like to include specific header file rather than a general header for a library. The reasons for this are numerous but the general idea is that the programmer should only include what he needs for the functionality that he actually uses in a particular situation.
A good example of including a specific header file rather than a general header file would be in the Boost type_traits library. The generalized Boost type_traits header is <boost/type_traits.hpp>. This header includes all the individual type traits headers, just as the C++ standard library the <type_traits> header includes all type traits. On the Boost side, however, it is possible to include header files for only the individual type traits being used in a TU instead of all type traits. When using the type_traits mod header the general C++ type_traits header is always included automatically. To have finer control over individual type traits header inclusion a programmer could use the low-level implementation header for type_traits and then manually include only the individual header file he is actually using when Boost is chosen as the dual library. The code might look like this:
#include <boost/cxx_dual/impl/type_traits.hpp> #if CXXD_HAS_STD_TYPE_TRAITS #include CXXD_TYPE_TRAITS_HEADER #else #include <boost/type_traits/add_const.hpp> #endif void SomeFunction() { // Code using CXXD_TYPE_TRAITS_NS::add_const }
When a mod header is included a namespace alias is created to refer to the constructs of that mod. The namespace alias merely uses the namespace macro for the dual library chosen to refer to that mod's namespace. For some programmers using a namespace alias might be overkill. They would rather use other more specific means to refer to some construct of the dual library chosen. For other programmers using a namespace alias is fine but they would rather use one reflecting their own naming preference rather than the name automatically created for any given mod header. Finally some programmers might decide to use the namespace macro directly rather than use a namespace alias at all. In any of the above cases the existence of a namespace macro can be used to create alternative means to refer to a dual library constructs.
Some programmers do not want to use a namespace in general in their code when they are using only specific constructs of a given library. In C++ you can do this with a using declaration:
#include <boost/cxx_dual/impl/type_traits.hpp> #include CXXD_TYPE_TRAITS_HEADER using CXXD_TYPE_TRAITS_NS::add_const; void SomeFunction() { // Code using add_const }
When using the low-level header a programmer might want to create his own namespace alias for referring in general to the constructs of the dual library chosen. This could obviously also be done when using the mod header but the automatically created namespace alias would be an extra namespace alias in that case which might never be used.
An example of creating one's own namespace alias could be:
#include <boost/cxx_dual/impl/type_traits.hpp> #include CXXD_TYPE_TRAITS_HEADER namespace mylib_tt = CXXD_TYPE_TRAITS_NS ; void SomeFunction() { // Code using mylib_tt::some_type_traits_construct }
Of course a programmer could choose to use the namespace macro directly rather than use a namespace alias at all:
#include <boost/cxx_dual/impl/type_traits.hpp> #include CXXD_TYPE_TRAITS_HEADER void SomeFunction() { // Code using CXXD_TYPE_TRAITS_NS::some_type_traits_construct }
You may just want to test whether or not the C++ standard library for a particular mod is supported or not, and write one-off code accordingly without using the CXXD dual library facility for the mod at all. While you could do this using a Boost Config macro the CXXD library provides a more regular syntactical naming convention for identifying whether a mod supports the C++ standard library or not:
#include <boost/cxx_dual/impl/type_traits.hpp> #if CXXD_HAS_STD_TYPE_TRAITS #include <type_traits> void SomeFunctionUsingCppTypeTraits() { // Code using std::some_trait } #endif
or:
#include <boost/cxx_dual/impl/type_traits.hpp> #if !CXXD_HAS_STD_TYPE_TRAITS #include <boost/type_traits.hpp> void SomeFunctionUsingBoostTraits() { // Code using boost::some_trait } #endif