-
Notifications
You must be signed in to change notification settings - Fork 0
Notes on updating
I would hope that if you find yourself still writing code in C++98, it is with the goal of eventually updating to a modern language standard. As such, you will likely find yourself in the position where you want to move away from this library and embrace the standard library tools. This is something you should do if you find yourself in C++11 or higher, as while this is a perfectly adequate library for C++98, the core language features added in C++11 and higher (constexpr, auto, and move semantics to name a few) mean that the standard library versions will outperform this library every time.
The macros DP_CPPXX, where XX is a number corresponding to a language standard, exist to aid in this process. When defined, they will selectively disable any library features which rely on some part of the standard which were removed between C++98 and that language standard. This was done to prevent some unrelated part of the library causing compilation to fail during the update process, so that e.g. you could test that you'd correctly swapped out dp::optional for std::optional without the fact that the smart pointers have a constructor for std::auto_ptr from preventing compilation and causing an unrelated mess which you would have to clean up.
This library was designed to mimic the interface of the standard closely, so for the most part updating is simple - change #include cpp98/foo.h to #include <foo>; and change dp::bar<...>(...); to std::bar<...>(...) and you should be good to go (though as always I strongly recommend appplying this change carefully and not just running a find-and-replace and calling it a day). However, there are one or two places in the library where I break with the standard interface because it is not possible to maintain it in C++98 and not cause some form of conflict. These cases are listed in the table below:
| This Library | Standard Equivalent |
|---|---|
dp::scoped_ptr<T>dp::lite_ptr<T>
|
std::unique_ptr<T> |
#include "cpp98/scoped_ptr.h |
#include <memory> |
#include "cpp98/shared_ptr.h |
#include <memory> |
#include "cpp98/null_ptr.h" |
No include needed for nullptr.#include <cstddef> needed for std::nullptr_t
|
dp::null_ptrdp::null_ptr_t
|
nullptrstd::nullptr_t
|
#include "cpp98/static_assert.h" |
No include needed |
dp::static_assert_98<condition>()STATIC_ASSERT(condition)
|
static_assert(condition) |
dp::unex(...) |
std::unexpected(...) |
#include "cpp98/reference_wrapper.h" |
#include <functional> |
#include "cpp98/byte.h |
#include <cstddef> |
dp::iterator_type<T>dp::const_iterator_type<T>dp::reverse_iterator_type<T>dp::const_reverse_iterator_type<T>
|
Likely not needed as formally spelled types. Most uses can be replaced by auto
|
Implicit conversion from dp::string_view types to std::string types |
Must be made into explicit conversions, e.g. std::string{my_string_view};
|
Note of course that the Borland types are not standard C++ so will not have standard equivalents. I recommend writing your own versions of these for the updated language standard if needed.
The features of this library cover a wide range of modern C++ language standards, from C++11 to C++23. To aid with the update process, I'll provide a broad-strokes list of the language standards from which each major feature of the library are adapted. This will not list, e.g., every algorithm from <algorithm> but will provide a good starting point for the larger and more commonly used types and allow you to see where you may need to find alternatives:
dp::scoped_ptr/std::unique_ptrshared_ptr<array>get_new_handler-
nullptrandstd::nullptr_t <ratio>reference_wrapperstatic_assert- All functions in
cpp98/string.hexcepterase/erase_ifadded to<string> <typeindex><type_traits>
<any>std::byte<optional><string_view>
<bit><span>-
std::erase&std::erase_ifforstd::stringandstd::vector
<expected>
Note that alternatives exist and can be found, and the library addons repo contains some. For example, gsl::span provides a version of <span> which is compatible with earlier language standards (and indeed was what std::span was adapted from); and std::erase simply formalises the erase-remove idiom which can be easily rewritten as needed.