Implement initial version of C++20 module boost.type_index (#15)

`#include <boost/type_index...` is now implicitly does `import boost.type_index` if the modules are supported 
All the library internals now have unconditional module level linkage.

Significant differences from https://anarthal.github.io/cppblog/modules3:
* `BOOST_TYPE_INDEX_USE_STD_MODULE` macro switch for `import std;` / `includes` while building module. This allows to use module in C++20 and even without usable  `std` module.
This commit is contained in:
Antony Polukhin
2025-05-12 17:35:17 +03:00
committed by GitHub
parent 14ee2581bd
commit dc78cf1825
26 changed files with 469 additions and 43 deletions

View File

@ -49,10 +49,10 @@ jobs:
compiler: clang++-14
cxxstd: "03,11,14,17,2a"
os: ubuntu-22.04
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang-19
cxxstd: "20,23"
os: ubuntu-24.04
install: clang-19 llvm-19 libclang-rt-19-dev libc++-19-dev libc++abi-19-dev clang-tools-19
runs-on: ${{matrix.os}}
@ -88,6 +88,31 @@ jobs:
./b2 -d0 headers
./b2 -j4 variant=debug tools/inspect/build
- name: Run modules tests wihtout 'import std;'
if: ${{matrix.toolset == 'clang-19'}}
run: |
cd ../boost-root/libs/type_index
mkdir build_module
cd build_module
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -GNinja -DCMAKE_CXX_COMPILER=clang++-19 ../test/cmake_subdir_test/
cmake --build .
ctest -V
cd ..
rm -rf build_module
- name: Run modules tests
if: false
#if: ${{matrix.toolset == 'clang-19'}}
run: |
cd ../boost-root/libs/type_index
mkdir build_module
cd build_module
cmake -DBUILD_TESTING=1 -DBOOST_USE_MODULES=1 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++ -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test/
cmake --build .
ctest -V
cd ..
rm -rf build_module
- name: Run tests
run: |
cd ../boost-root
@ -175,6 +200,36 @@ jobs:
cmd /c bootstrap
b2 -d0 headers
- name: Run modules tests
if: ${{matrix.toolset == 'msvc-14.3'}}
shell: cmd
run: |
choco install --no-progress ninja
call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64
cd ../boost-root/libs/type_index
mkdir build_module
cd build_module
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test/
cmake --build .
ctest --no-tests=error -V
cd ..
rm -rf build_module
- name: Run modules tests without 'import std;'
if: ${{matrix.toolset == 'msvc-14.3'}}
shell: cmd
run: |
choco install --no-progress ninja
call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64
cd ../boost-root/libs/type_index
mkdir build_module
cd build_module
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -DCMAKE_CXX_STANDARD=20 -G Ninja ../test/cmake_subdir_test/
cmake --build .
ctest --no-tests=error -V
cd ..
rm -rf build_module
- name: Run tests
shell: cmd
run: |

View File

@ -3,17 +3,35 @@
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.20)
cmake_minimum_required(VERSION 3.5...3.31)
project(boost_type_index VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
add_library(boost_type_index INTERFACE)
if (BOOST_USE_MODULES)
add_library(boost_type_index)
target_sources(boost_type_index PUBLIC
FILE_SET modules_public TYPE CXX_MODULES FILES modules/boost_type_index.cppm
)
target_compile_features(boost_type_index PUBLIC cxx_std_20)
target_compile_definitions(boost_type_index PUBLIC BOOST_USE_MODULES)
if (CMAKE_CXX_COMPILER_IMPORT_STD)
target_compile_definitions(boost_type_index PRIVATE BOOST_TYPE_INDEX_USE_STD_MODULE)
message(STATUS "Using `import std;`")
else()
message(STATUS "`import std;` is not awailable")
endif()
set(__scope PUBLIC)
else()
add_library(boost_type_index INTERFACE)
set(__scope INTERFACE)
endif()
target_include_directories(boost_type_index ${__scope} include)
add_library(Boost::type_index ALIAS boost_type_index)
target_include_directories(boost_type_index INTERFACE include)
target_link_libraries(boost_type_index
INTERFACE
${__scope}
Boost::config
Boost::container_hash
Boost::core

View File

@ -1,6 +1,6 @@
[library Boost.TypeIndex
[quickbook 1.6]
[version 4.1]
[version 4.2]
[copyright 2012-2025 Antony Polukhin]
[category Language Features Emulation]
[license
@ -314,6 +314,40 @@ Sometimes there may be a need to create your own type info system. This may be u
[endsect]
[section C++20 module]
[caution C++20 module support is on early stage, targets, flags and behavior may change in the future]
If using modern CMake define CMake option `-DBOOST_USE_MODULES=1` to build a C++20 module and
make the `Boost::type_index` CMake target provide it. After that an explicit usage of C++20 module `boost.type_index` is allowed:
[import ../modules/usage_sample.cpp]
[type_index_module_example]
The `Boost::type_index` CMake target gives an ability to mix includes and imports of the library in different translation units. Moreover,
if `BOOST_USE_MODULES` macro is defined then all the `boost/type_index/...` includes implicilty do `import boost.type_index;` to give all the
benifits of modules without changing the existing code.
[note For better compile times make sure that `import std;` is available when building the `boost.type_index` module (in CMake logs there should be
a 'Using `import std;`' message). ]
If not using CMake, then the module could be build manually from the `modules/boost_type_index.cppm` file.
For manual module build the following commands can be used for clang compiler:
```
cd type_index/modules
clang++ -I ../include -std=c++20 --precompile -x c++-module boost_type_index.cppm
```
After that, the module could be used in the following way:
```
clang++ -std=c++20 -fmodule-file=boost_type_index.pcm boost_type_index.pcm usage_sample.cpp
```
[endsect]
[section Space and Performance]

View File

@ -14,7 +14,7 @@
/// By inclusion of this file most optimal type index classes will be included and used
/// as a boost::typeindex::type_index and boost::typeindex::type_info.
#include <boost/config.hpp>
#include <boost/type_index/detail/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
@ -49,8 +49,12 @@
#define BOOST_TYPE_INDEX_REGISTER_CLASS
#endif
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
namespace boost { namespace typeindex {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
#if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED)
/// \def BOOST_TYPE_INDEX_FUNCTION_SIGNATURE
@ -257,9 +261,11 @@ inline type_index type_id_runtime(const T& runtime_val) noexcept {
return type_index::type_id_runtime(runtime_val);
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_HPP

View File

@ -18,12 +18,19 @@
/// It is used in situations when typeid() method is not available or
/// BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY macro is defined.
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <boost/type_index/type_index_facade.hpp>
#include <boost/type_index/detail/compile_time_type_info.hpp>
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <cstring>
#include <type_traits>
#include <boost/container_hash/hash.hpp>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
@ -64,6 +71,8 @@ public:
} // namespace detail
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
/// Helper method for getting detail::ctti_data of a template parameter T.
template <class T>
inline const detail::ctti_data& ctti_construct() noexcept {
@ -132,6 +141,8 @@ public:
inline static ctti_type_index type_id_runtime(const T& variable) noexcept;
};
BOOST_TYPE_INDEX_END_MODULE_EXPORT
inline const ctti_type_index::type_info_t& ctti_type_index::type_info() const noexcept {
return *reinterpret_cast<const detail::ctti_data*>(data_);
@ -197,8 +208,9 @@ inline std::size_t ctti_type_index::hash_code() const noexcept {
return boost::hash_range(raw_name(), raw_name() + get_raw_name_length());
}
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP

View File

@ -13,10 +13,12 @@
/// \brief Contains helper macros and implementation details of boost::typeindex::ctti_type_index.
/// Not intended for inclusion from user's code.
#include <boost/config.hpp>
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <cstring>
#include <type_traits>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once

View File

@ -0,0 +1,32 @@
//
// Copyright 2013-2025 Antony Polukhin.
//
//
// 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)
//
#ifndef BOOST_TYPE_INDEX_DETAIL_CONFIG_HPP
#define BOOST_TYPE_INDEX_DETAIL_CONFIG_HPP
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#endif
#ifdef BOOST_TYPE_INDEX_INTERFACE_UNIT
# define BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT export {
# define BOOST_TYPE_INDEX_END_MODULE_EXPORT }
#else
# define BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
# define BOOST_TYPE_INDEX_END_MODULE_EXPORT
#endif
#if defined(BOOST_USE_MODULES) && !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
import boost.type_index;
#endif
#endif // BOOST_TYPE_INDEX_DETAIL_CONFIG_HPP

View File

@ -19,15 +19,23 @@
# pragma once
#endif
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
namespace boost { namespace typeindex { namespace detail {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
template <class T>
inline const ctti_data& ctti_construct_typeid_ref(const T*) noexcept {
return boost::typeindex::ctti_construct<T>();
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}}} // namespace boost::typeindex::detail
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
/// @cond
#define BOOST_TYPE_INDEX_REGISTER_CLASS \
virtual const boost::typeindex::detail::ctti_data& boost_type_index_type_id_runtime_() const noexcept { \

View File

@ -19,15 +19,23 @@
# pragma once
#endif
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
namespace boost { namespace typeindex { namespace detail {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
template <class T>
inline const stl_type_index::type_info_t& stl_construct_typeid_ref(const T*) noexcept {
return typeid(T);
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}}} // namespace boost::typeindex::detail
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
/// @cond
#define BOOST_TYPE_INDEX_REGISTER_CLASS \
virtual const boost::typeindex::stl_type_index::type_info_t& boost_type_index_type_id_runtime_() const noexcept { \

View File

@ -9,6 +9,8 @@
#ifndef BOOST_TYPE_INDEX_RUNTIME_CAST_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_HPP
#include <boost/type_index/detail/config.hpp>
/// \file runtime_cast.hpp
/// \brief Contains the basic utilities necessary to fully emulate
/// dynamic_cast for language level constructs (raw pointers and references).

View File

@ -13,21 +13,25 @@
/// \brief Contains the overload of boost::typeindex::runtime_pointer_cast for
/// boost::shared_ptr types.
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <type_traits>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost {
template<class T> class shared_ptr;
}
namespace boost { namespace typeindex {
/// \brief Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
/// \brief Creates a new instance of smart pointer whose stored pointer is obtained from u's
/// stored pointer using a runtime_cast.
///
/// The new shared_ptr will share ownership with u, except that it is empty if the runtime_cast
@ -37,14 +41,18 @@ namespace boost { namespace typeindex {
/// \return If there exists a valid conversion from U* to T*, returns a boost::shared_ptr<T>
/// that points to an address suitably offset from u.
/// If no such conversion exists, returns boost::shared_ptr<T>();
template<typename T, typename U>
boost::shared_ptr<T> runtime_pointer_cast(boost::shared_ptr<U> const& u) {
template<typename T, typename U, template <class> class SmartPointer>
auto runtime_pointer_cast(SmartPointer<U> const& u) -> decltype(u.use_count(), SmartPointer<T>()) {
T* value = detail::runtime_cast_impl<T>(u.get(), std::is_base_of<T, U>());
if(value)
return boost::shared_ptr<T>(u, value);
return boost::shared_ptr<T>();
return SmartPointer<T>(u, value);
return SmartPointer<T>();
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_BOOST_SHARED_PTR_CAST_HPP

View File

@ -19,7 +19,9 @@
#include <boost/type_index.hpp>
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <type_traits>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once

View File

@ -12,16 +12,22 @@
/// \file pointer_class.hpp
/// \brief Contains the function overloads of boost::typeindex::runtime_cast for
/// pointer types.
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <boost/type_index.hpp>
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy.
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
/// \tparam U A complete class type of the source instance, u.
@ -68,6 +74,10 @@ T const* runtime_pointer_cast(U const* u) noexcept {
return detail::runtime_cast_impl<T>(u, std::is_base_of<T, U>());
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_POINTER_CAST_HPP

View File

@ -13,18 +13,27 @@
/// \brief Contains the overload of boost::typeindex::runtime_cast for
/// reference types.
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#include <boost/throw_exception.hpp>
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <memory>
#include <type_traits>
#include <boost/throw_exception.hpp>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
/// \brief Indicates that runtime_cast was unable to perform the desired cast operation
/// because the source instance was not also an instance of the target type.
struct BOOST_SYMBOL_VISIBLE bad_runtime_cast : std::exception
@ -60,6 +69,10 @@ typename std::add_lvalue_reference<const T>::type runtime_cast(U const& u) {
return *value;
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REFERENCE_CAST_HPP

View File

@ -12,14 +12,21 @@
/// \file register_runtime_class.hpp
/// \brief Contains the macros BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST and
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
#include <boost/type_index/detail/config.hpp>
#include <boost/type_index.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex { namespace detail {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
template<typename T>
inline type_index runtime_class_construct_type_id(T const*) {
return boost::typeindex::type_id<T>();
@ -39,8 +46,12 @@ const void* find_instance(boost::typeindex::type_index const& idx, const Self* s
return boost::typeindex::detail::find_instance<OtherBases...>(idx, self);
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}}} // namespace boost::typeindex::detail
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
/// \def BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
/// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast

View File

@ -13,8 +13,15 @@
/// \brief Contains the overload of boost::typeindex::runtime_pointer_cast for
/// std::shared_ptr types.
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <memory>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
@ -22,6 +29,8 @@
namespace boost { namespace typeindex {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
/// \brief Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's
/// stored pointer using a runtime_cast.
///
@ -40,6 +49,10 @@ std::shared_ptr<T> runtime_pointer_cast(std::shared_ptr<U> const& u) {
return std::shared_ptr<T>();
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_STD_SHARED_PTR_CAST_HPP

View File

@ -19,6 +19,10 @@
/// When typeid() is disabled or BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY macro
/// is defined boost::typeindex::ctti is usually used instead of boost::typeindex::stl_type_index.
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <boost/type_index/type_index_facade.hpp>
// MSVC is capable of calling typeid(T) even when RTTI is off
@ -26,12 +30,15 @@
#error "File boost/type_index/stl_type_index.ipp is not usable when typeid() is not available."
#endif
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <typeinfo>
#include <cstring> // std::strcmp, std::strlen, std::strstr
#include <stdexcept>
#include <type_traits>
#include <boost/throw_exception.hpp>
#include <boost/core/demangle.hpp>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
@ -39,6 +46,8 @@
namespace boost { namespace typeindex {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
/// \class stl_type_index
/// This class is a wrapper around std::type_info, that workarounds issues and provides
/// much more rich interface. \b For \b description \b of \b functions \b see type_index_facade.
@ -93,6 +102,8 @@ public:
inline static stl_type_index type_id_runtime(const T& value) noexcept;
};
BOOST_TYPE_INDEX_END_MODULE_EXPORT
inline const stl_type_index::type_info_t& stl_type_index::type_info() const noexcept {
return *data_;
}
@ -111,7 +122,7 @@ inline const char* stl_type_index::name() const noexcept {
}
inline std::string stl_type_index::pretty_name() const {
static const char cvr_saver_name[] = "boost::typeindex::detail::cvr_saver<";
static const char cvr_saver_name[] = "boost::typeindex::detail::cvr_saver";
static BOOST_CONSTEXPR_OR_CONST std::string::size_type cvr_saver_name_len = sizeof(cvr_saver_name) - 1;
// In case of MSVC demangle() is a no-op, and name() already returns demangled name.
@ -131,6 +142,12 @@ inline std::string stl_type_index::pretty_name() const {
if (b) {
b += cvr_saver_name_len;
// Trim everuthing till '<'. In modules the name could be boost::typeindex::detail::cvr_saver@boost.type_index<
while (*b != '<') { // the string is zero terminated, we won't exceed the buffer size
++ b;
}
++b;
// Trim leading spaces
while (*b == ' ') { // the string is zero terminated, we won't exceed the buffer size
++ b;
@ -231,4 +248,6 @@ inline stl_type_index stl_type_index::type_id_runtime(const T& value) noexcept {
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_STL_TYPE_INDEX_HPP

View File

@ -9,19 +9,28 @@
#ifndef BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP
#define BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP
#include <boost/config.hpp>
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/type_index/detail/config.hpp>
#if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#if !defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#include <string>
#include <cstring>
#include <type_traits>
#include <iosfwd> // for std::basic_ostream
#include <boost/config.hpp>
#include <boost/container_hash/hash_fwd.hpp>
#endif
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
BOOST_TYPE_INDEX_BEGIN_MODULE_EXPORT
/// \class type_index_facade
///
/// This class takes care about the comparison operators, hash functions and
@ -274,7 +283,11 @@ inline std::size_t hash_value(const type_index_facade<Derived, TypeInfo>& lhs) n
return static_cast<Derived const&>(lhs).hash_code();
}
BOOST_TYPE_INDEX_END_MODULE_EXPORT
}} // namespace boost::typeindex
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_TYPE_INDEX_INTERFACE_UNIT)
#endif // BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP

View File

@ -0,0 +1,55 @@
// Copyright (c) 2016-2025 Antony Polukhin
//
// 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)
// To compile manually use a command like the folowing:
// clang++ -I ../include -std=c++20 --precompile -x c++-module pfr.cppm
module;
#include <version>
#include <cstddef>
#include <cstdint>
#include <boost/config.hpp>
#include <boost/container_hash/hash_fwd.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/core/demangle.hpp>
#include <boost/throw_exception.hpp>
#ifndef BOOST_TYPE_INDEX_USE_STD_MODULE
#include <cstring>
#include <iosfwd>
#include <memory>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <type_traits>
#endif
#define BOOST_TYPE_INDEX_INTERFACE_UNIT
export module boost.type_index;
#ifdef BOOST_TYPE_INDEX_USE_STD_MODULE
// Should not be in the global module fragment
// https://eel.is/c++draft/module#global.frag-1
import std;
#endif
#ifdef __clang__
# pragma clang diagnostic ignored "-Winclude-angled-in-module-purview"
#endif
#include <boost/type_index.hpp>
#include <boost/type_index/ctti_type_index.hpp>
#include <boost/type_index/runtime_cast.hpp>
#include <boost/type_index/runtime_cast/boost_shared_ptr_cast.hpp>
#include <boost/type_index/runtime_cast/pointer_cast.hpp>
#include <boost/type_index/runtime_cast/reference_cast.hpp>
#include <boost/type_index/runtime_cast/register_runtime_class.hpp>
#include <boost/type_index/runtime_cast/std_shared_ptr_cast.hpp>
#include <boost/type_index/stl_type_index.hpp>
#include <boost/type_index/type_index_facade.hpp>

18
modules/usage_sample.cpp Normal file
View File

@ -0,0 +1,18 @@
// Copyright (c) 2016-2025 Antony Polukhin
//
// 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)
// To compile manually use a command like the folowing:
// clang++ -std=c++20 -fmodule-file=type_index.pcm type_index.pcm usage_sample.cpp
//[type_index_module_example
#include <iostream>
import boost.type_index;
int main() {
std::cout << boost::typeindex::type_id_with_cvr<const int>(); // Outputs: const int
}
//]

View File

@ -0,0 +1,13 @@
// Copyright (c) 2016-2025 Antony Polukhin
//
// 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 <iostream>
import boost.type_index;
void do_something(std::ostream& os) {
os << boost::typeindex::type_id_with_cvr<const int>();
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2016-2025 Antony Polukhin
//
// 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 <iostream>
#include <boost/type_index.hpp>
void do_something(std::ostream& os);
int main() {
do_something(std::cout);
std::cout << '\n';
std::cout << boost::typeindex::type_id_with_cvr<const int>(); // Outputs: const int
}

View File

@ -50,10 +50,10 @@ exe testing_crossmodule_anonymous_no_rtti : testing_crossmodule_anonymous.cpp te
test-suite type_index
:
[ run type_index_test.cpp /boost/lexical_cast//boost_lexical_cast ]
[ run type_index_test.cpp ]
[ run type_index_runtime_cast_test.cpp /boost/smart_ptr//boost_smart_ptr ]
[ run type_index_constexpr_test.cpp ]
[ run type_index_test.cpp /boost/lexical_cast//boost_lexical_cast : : : <rtti>off $(norttidefines) : type_index_test_no_rtti ]
[ run type_index_test.cpp : : : <rtti>off $(norttidefines) : type_index_test_no_rtti ]
[ run ctti_print_name.cpp : : : <test-info>always_show_run_output ]
[ run testing_crossmodule.cpp test_lib_rtti ]
[ run testing_crossmodule.cpp test_lib_nortti : : : <rtti>off $(norttidefines) : testing_crossmodule_no_rtti ]

View File

@ -0,0 +1,52 @@
# Copyright (c) 2016-2025 Antony Polukhin
# 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
cmake_minimum_required(VERSION 3.5...4.0)
project(type_index_subdir_test LANGUAGES CXX)
add_subdirectory(../../../assert boostorg/assert)
add_subdirectory(../../../core boostorg/core)
add_subdirectory(../../../config boostorg/config)
add_subdirectory(../../../container_hash boostorg/container_hash)
add_subdirectory(../../../describe boostorg/describe)
add_subdirectory(../../../detail boostorg/detail)
add_subdirectory(../../../integer boostorg/integer)
add_subdirectory(../../../move boostorg/move)
add_subdirectory(../../../mp11 boostorg/mp11)
add_subdirectory(../../../preprocessor boostorg/preprocessor)
add_subdirectory(../../../smart_ptr boostorg/smart_ptr)
add_subdirectory(../../../static_assert boostorg/static_assert)
add_subdirectory(../../../throw_exception boostorg/throw_exception)
add_subdirectory(../../../type_traits boostorg/type_traits)
add_subdirectory(../../ boostorg/type_index)
enable_testing()
if (BOOST_USE_MODULES)
add_executable(boost_type_index_module_usage ../../modules/usage_sample.cpp)
target_link_libraries(boost_type_index_module_usage PRIVATE Boost::type_index)
add_test(NAME boost_type_index_module_usage COMMAND boost_type_index_module_usage)
# Make sure that mixing includes and imports is fine for different TU
add_executable(boost_type_index_module_usage_mu ../../modules/usage_test_mu1.cpp ../../modules/usage_test_mu2.cpp)
target_link_libraries(boost_type_index_module_usage_mu PRIVATE Boost::type_index)
add_test(NAME boost_type_index_module_usage_mu COMMAND boost_type_index_module_usage_mu)
endif()
list(APPEND RUN_TESTS_SOURCES
compare_ctti_stl.cpp
ctti_print_name.cpp
track_13621.cpp
type_index_runtime_cast_test.cpp
type_index_test.cpp
)
foreach (testsourcefile ${RUN_TESTS_SOURCES})
get_filename_component(testname ${testsourcefile} NAME_WLE)
add_executable(${PROJECT_NAME}_${testname} ../${testsourcefile})
target_link_libraries(${PROJECT_NAME}_${testname} Boost::type_index Boost::smart_ptr)
add_test(NAME ${PROJECT_NAME}_${testname} COMMAND ${PROJECT_NAME}_${testname})
endforeach()

View File

@ -34,8 +34,8 @@ void compare()
typedef boost::typeindex::ctti_type_index ctti;
typedef boost::typeindex::stl_type_index stl;
BOOST_TEST_EQ(
ctti::type_id<int>().pretty_name(),
stl::type_id<int>().pretty_name()
ctti::type_id<T>().pretty_name(),
stl::type_id<T>().pretty_name()
);
}
@ -44,14 +44,15 @@ int main()
{
compare<void>();
compare<int>();
compare<double*>();
compare<const double&>();
#ifndef _MSC_VER // may add `class` to the type name
compare<my_namespace1::my_class>();
compare<my_namespace3::my_template<
my_namespace1::my_class,
my_namespace2::my_class> >();
#endif
return boost::report_errors();
}

View File

@ -7,7 +7,7 @@
#include <boost/type_index.hpp>
#include <boost/lexical_cast.hpp>
#include <sstream>
#include <boost/core/lightweight_test.hpp>
@ -209,15 +209,20 @@ void type_id_storing_modifiers_vs_nonstoring()
BOOST_TEST(t1.pretty_name() == "const int" || t1.pretty_name() == "int const");
}
void type_index_stream_operator_via_lexical_cast_testing()
void type_index_stream_operator_via_stringstream_testing()
{
using namespace boost::typeindex;
std::string s_int2 = boost::lexical_cast<std::string>(type_id<int>());
BOOST_TEST_EQ(s_int2, "int");
std::string s_double2 = boost::lexical_cast<std::string>(type_id<double>());
BOOST_TEST_EQ(s_double2, "double");
{
std::ostringstream oss;
oss << type_id<int>();
BOOST_TEST_EQ(oss.str(), "int");
}
{
std::ostringstream oss;
oss << type_id<double>();
BOOST_TEST_EQ(oss.str(), "double");
}
}
void type_index_stripping_cvr_test()
@ -386,7 +391,7 @@ int main() {
type_id_storing_modifiers();
type_id_storing_modifiers_vs_nonstoring();
type_index_stream_operator_via_lexical_cast_testing();
type_index_stream_operator_via_stringstream_testing();
type_index_stripping_cvr_test();
type_index_user_defined_class_test();