From 0422aebeb80deac7a69757faf121f35b9beba5cd Mon Sep 17 00:00:00 2001 From: Adder Date: Tue, 13 Jun 2023 23:29:56 +0300 Subject: [PATCH 1/5] `integral_constant`: MPL interop: Avoid `reinterpret_cast`. Conversion between pointers to unrelated types `Source` and `Target` can be done with two `static_cast`'s ("upcast" to pointer to cv-void followed by "downcast") => (IMO) it should be done with `static_cast` (in order not to give the impression that `reinterpret_cast` really is needed): `T *ptr_target = static_cast (static_cast (ptr_source));` (Maybe that was the original intent of introducing `pdata`.) --- include/boost/type_traits/integral_constant.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/type_traits/integral_constant.hpp b/include/boost/type_traits/integral_constant.hpp index 2592bcb..47699be 100644 --- a/include/boost/type_traits/integral_constant.hpp +++ b/include/boost/type_traits/integral_constant.hpp @@ -61,7 +61,7 @@ namespace boost{ { static const char data[sizeof(long)] = { 0 }; static const void* pdata = data; - return *(reinterpret_cast*>(pdata)); + return *static_cast*>(pdata); } BOOST_CONSTEXPR operator T()const { return val; } }; @@ -81,7 +81,7 @@ namespace boost{ { static const char data[sizeof(long)] = { 0 }; static const void* pdata = data; - return *(reinterpret_cast*>(pdata)); + return *static_cast*>(pdata); } BOOST_CONSTEXPR operator bool()const { return val; } }; From ff0ae13c648bd17ba436717933f2a38d8243738d Mon Sep 17 00:00:00 2001 From: Adder Date: Mon, 6 Jan 2025 00:24:20 +0200 Subject: [PATCH 2/5] `integral_constant`: MPL interop: Avoid one function-local `static` object. If the compiler does not optimize away the `pdata` function-local `static` object, it ends up occupying space in the data section and it is going to need a corresponding relocation entry (just in case the module is not loaded at the desired address, as is the case with ASLR in Windows Vista and later and in modern versions of Linux). I admit that, for the current code, both MSVC and GCC manage to optimize away `pdata` even if it is `static`. But Boost should be an example of good coding which can be applied even to more complicated source code, e.g. to source code which calls `opaque_function (&pdata)` (in which case, if `pdata` is static, both MSVC and GCC do emit an extra relocation). And for other more complex cases, a function-local static-storage-duration object costs even more (as compared to a function-local automatic-storage-duration object given C++11 rules for "thread-safe" initialization of function-local `static`s. And I wish to re-iterate that, in my opinion, a good way to cast a pointer-to-one-type to a pointer-to-an-unrelated-type is not by `reinterpret_cast` (which by the way makes `pdata` not needed any more), but by using pointer to (possibly cv-qualified) `void` as an intermediary pointer type: ``` return static_cast (static_cast (pointer_to_source)) ``` or: ``` const void *const intermediary (pointer_to_source); // Not `static` for the general case. return static_cast (intermediary); ``` Therefore, if the authors kindly agree, we can make this code an example for this style. --- include/boost/type_traits/integral_constant.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/type_traits/integral_constant.hpp b/include/boost/type_traits/integral_constant.hpp index 47699be..9a65df3 100644 --- a/include/boost/type_traits/integral_constant.hpp +++ b/include/boost/type_traits/integral_constant.hpp @@ -60,7 +60,7 @@ namespace boost{ operator const mpl::integral_c& ()const { static const char data[sizeof(long)] = { 0 }; - static const void* pdata = data; + const void* const pdata = data; return *static_cast*>(pdata); } BOOST_CONSTEXPR operator T()const { return val; } @@ -80,7 +80,7 @@ namespace boost{ operator const mpl::bool_& ()const { static const char data[sizeof(long)] = { 0 }; - static const void* pdata = data; + const void* const pdata = data; return *static_cast*>(pdata); } BOOST_CONSTEXPR operator bool()const { return val; } From f31a9da4d803efe0788b7fd2428f5787ad59edea Mon Sep 17 00:00:00 2001 From: Adder Date: Tue, 7 Jan 2025 00:19:34 +0200 Subject: [PATCH 3/5] `integral_constant`: As per `std`: Mark `operator T` as `noexcept`. In the C++ Standard Library, `std::integral_constant` has its `operator T` marked as `noexcept`: https://timsong-cpp.github.io/cppwp/meta.help We hereby do the same for the Boost version. --- include/boost/type_traits/integral_constant.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/type_traits/integral_constant.hpp b/include/boost/type_traits/integral_constant.hpp index 9a65df3..284ed02 100644 --- a/include/boost/type_traits/integral_constant.hpp +++ b/include/boost/type_traits/integral_constant.hpp @@ -63,7 +63,7 @@ namespace boost{ const void* const pdata = data; return *static_cast*>(pdata); } - BOOST_CONSTEXPR operator T()const { return val; } + BOOST_CONSTEXPR operator T()const BOOST_NOEXCEPT { return val; } }; template @@ -83,7 +83,7 @@ namespace boost{ const void* const pdata = data; return *static_cast*>(pdata); } - BOOST_CONSTEXPR operator bool()const { return val; } + BOOST_CONSTEXPR operator bool()const BOOST_NOEXCEPT { return val; } }; template From 4126ca650cb318f034420fac69b9101e16bc13c1 Mon Sep 17 00:00:00 2001 From: Adder Date: Tue, 7 Jan 2025 00:43:06 +0200 Subject: [PATCH 4/5] `integral_constant`: As per `std`: Add `operator()`. In the C++ Standard Library, `std::integral_constant` has `operator()`: https://timsong-cpp.github.io/cppwp/meta.help We hereby add `operator()` for the Boost version. --- .../boost/type_traits/integral_constant.hpp | 2 ++ test/integral_constant_test.cpp | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100755 test/integral_constant_test.cpp diff --git a/include/boost/type_traits/integral_constant.hpp b/include/boost/type_traits/integral_constant.hpp index 284ed02..7424c86 100644 --- a/include/boost/type_traits/integral_constant.hpp +++ b/include/boost/type_traits/integral_constant.hpp @@ -64,6 +64,7 @@ namespace boost{ return *static_cast*>(pdata); } BOOST_CONSTEXPR operator T()const BOOST_NOEXCEPT { return val; } + BOOST_CONSTEXPR T operator()()const BOOST_NOEXCEPT { return val; } }; template @@ -84,6 +85,7 @@ namespace boost{ return *static_cast*>(pdata); } BOOST_CONSTEXPR operator bool()const BOOST_NOEXCEPT { return val; } + BOOST_CONSTEXPR bool operator()()const BOOST_NOEXCEPT { return val; } }; template diff --git a/test/integral_constant_test.cpp b/test/integral_constant_test.cpp new file mode 100755 index 0000000..6938d5d --- /dev/null +++ b/test/integral_constant_test.cpp @@ -0,0 +1,28 @@ +// Copyright 2025 DoctorNoobingstoneIPresume +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +int main () +{ + // [2025-01-07] Adapted from example in https://en.cppreference.com/w/cpp/types/integral_constant ... + + using two_t = boost::integral_constant ; + using four_t = boost::integral_constant ; + + BOOST_STATIC_ASSERT ((! boost::is_same ::value)); + BOOST_STATIC_ASSERT ((two_t::value * 2 == four_t::value)); + BOOST_STATIC_ASSERT ((two_t () << 1 == four_t ())); + BOOST_STATIC_ASSERT ((two_t () () << 1 == four_t () ())); + + enum class E {e0, e1}; + using c0 = boost::integral_constant ; + using c1 = boost::integral_constant ; + BOOST_STATIC_ASSERT ((c0::value != E::e1)); + BOOST_STATIC_ASSERT ((c0 () == E::e0)); + BOOST_STATIC_ASSERT ((boost::is_same ::value)); +} From 5329d1d4978d737eb0b49e114156b262a53ca6f2 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Mon, 21 Apr 2025 13:40:42 +0100 Subject: [PATCH 5/5] Disable constexpr test in C++03. --- test/integral_constant_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integral_constant_test.cpp b/test/integral_constant_test.cpp index 6938d5d..fc4cb35 100755 --- a/test/integral_constant_test.cpp +++ b/test/integral_constant_test.cpp @@ -11,6 +11,8 @@ int main () { // [2025-01-07] Adapted from example in https://en.cppreference.com/w/cpp/types/integral_constant ... +#ifndef BOOST_NO_CXX11_CONSTEXPR + using two_t = boost::integral_constant ; using four_t = boost::integral_constant ; @@ -25,4 +27,5 @@ int main () BOOST_STATIC_ASSERT ((c0::value != E::e1)); BOOST_STATIC_ASSERT ((c0 () == E::e0)); BOOST_STATIC_ASSERT ((boost::is_same ::value)); +#endif }