├── include ├── pfr │ ├── detail │ │ ├── size_t_.hpp │ │ ├── core.hpp │ │ ├── core_name.hpp │ │ ├── config.hpp │ │ ├── rvalue_t.hpp │ │ ├── stdarray.hpp │ │ ├── unsafe_declval.hpp │ │ ├── possible_reflectable.hpp │ │ ├── tie_from_structure_tuple.hpp │ │ ├── core_name14_disabled.hpp │ │ ├── for_each_field.hpp │ │ ├── fake_object.hpp │ │ ├── stdtuple.hpp │ │ ├── size_array.hpp │ │ ├── for_each_field_impl.hpp │ │ ├── io.hpp │ │ ├── core17.hpp │ │ ├── make_integer_sequence.hpp │ │ ├── detectors.hpp │ │ ├── make_flat_tuple_of_references.hpp │ │ ├── offset_based_getter.hpp │ │ ├── sequence_tuple.hpp │ │ ├── core14_loophole.hpp │ │ ├── functional.hpp │ │ ├── core_name20_static.hpp │ │ └── fields_count.hpp │ ├── traits_fwd.hpp │ ├── tuple_size.hpp │ ├── traits.hpp │ ├── core_name.hpp │ ├── io.hpp │ ├── functions_for.hpp │ ├── ops_fields.hpp │ ├── config.hpp │ ├── io_fields.hpp │ ├── functors.hpp │ ├── ops.hpp │ └── core.hpp └── pfr.hpp ├── example ├── motivating_example0.cpp ├── get.cpp ├── get_name.cpp ├── sample_printing.cpp └── quick_examples.cpp ├── index.html ├── modules ├── usage_test_mu2.cpp ├── usage_test_mu1.cpp ├── boost_pfr.cppm └── usage_sample.cpp ├── LICENSE_1_0.txt ├── CMakeLists.txt ├── doc └── Jamfile.v2 ├── README.md └── misc ├── generate_cpp17.py └── generate_fields_names_big.cpp.py /include/pfr/detail/size_t_.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_SIZE_T_HPP 7 | #define PFR_DETAIL_SIZE_T_HPP 8 | #pragma once 9 | 10 | #if !defined(PFR_INTERFACE_UNIT) 11 | #include 12 | #include 13 | #endif 14 | 15 | namespace pfr { namespace detail { 16 | 17 | ///////////////////// General utility stuff 18 | template 19 | using size_t_ = std::integral_constant; 20 | 21 | }} // namespace pfr::detail 22 | 23 | #endif // PFR_DETAIL_SIZE_T_HPP 24 | -------------------------------------------------------------------------------- /include/pfr.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_HPP 7 | #define PFR_HPP 8 | 9 | /// \file pfr.hpp 10 | /// Includes all the Boost.PFR headers 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #endif // PFR_HPP 26 | -------------------------------------------------------------------------------- /include/pfr/traits_fwd.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Denis Mikhailov 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_TRAITS_FWD_HPP 7 | #define PFR_DETAIL_TRAITS_FWD_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #if !defined(PFR_USE_MODULES) || defined(PFR_INTERFACE_UNIT) 13 | 14 | namespace pfr { 15 | 16 | PFR_BEGIN_MODULE_EXPORT 17 | 18 | template 19 | struct is_reflectable; 20 | 21 | PFR_END_MODULE_EXPORT 22 | 23 | } // namespace pfr 24 | 25 | #endif // #if !defined(PFR_USE_MODULES) || defined(PFR_INTERFACE_UNIT) 26 | 27 | #endif // PFR_DETAIL_TRAITS_FWD_HPP 28 | 29 | -------------------------------------------------------------------------------- /example/motivating_example0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | 7 | //[pfr_motivating_example 8 | #include 9 | #include 10 | 11 | #include "pfr.hpp" 12 | 13 | struct some_person { 14 | std::string name; 15 | unsigned birth_year; 16 | }; 17 | 18 | int main() { 19 | some_person val{"Edgar Allan Poe", 1809}; 20 | 21 | std::cout << pfr::get<0>(val) // No macro! 22 | << " was born in " << pfr::get<1>(val); // Works with any aggregate initializables! 23 | 24 | std::cout << pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809} 25 | } 26 | //] 27 | -------------------------------------------------------------------------------- /include/pfr/detail/core.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_CORE_HPP 7 | #define PFR_DETAIL_CORE_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | // Each core provides `pfr::detail::tie_as_tuple` and 13 | // `pfr::detail::for_each_field_dispatcher` functions. 14 | // 15 | // The whole PFR library is build on top of those two functions. 16 | #if PFR_USE_CPP17 17 | # include 18 | #elif PFR_USE_LOOPHOLE 19 | # include 20 | #else 21 | # include 22 | #endif 23 | 24 | #endif // PFR_DETAIL_CORE_HPP 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | Boost.Stacktrace 17 | 27 | 28 | 29 |

30 | Automatic redirection failed, please go to 31 | ../../doc/html/boost_pfr.html 32 |

33 |

34 | © 2014-2024 Antony Polukhin 35 |

36 | 37 | 38 | -------------------------------------------------------------------------------- /modules/usage_test_mu2.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // To compile manually use a command like the folowing: 7 | // clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp 8 | 9 | #include 10 | #include 11 | 12 | import pfr; 13 | 14 | struct some_person { 15 | std::string name; 16 | unsigned birth_year; 17 | }; 18 | 19 | void mu1_act(); 20 | 21 | int main() { 22 | mu1_act(); 23 | 24 | some_person val{"Joseph Brodsky", 1940}; 25 | 26 | std::cout << pfr::get<0>(val) // No macro! 27 | << " was born in " << pfr::get<1>(val); // Works with any aggregate! 28 | 29 | std::cout << '\n' << pfr::io(val); 30 | std::cout << "\n." << pfr::get_name<0, some_person>() 31 | << '=' << val.name << '\n'; 32 | } 33 | -------------------------------------------------------------------------------- /include/pfr/detail/core_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov. 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | 7 | // Initial implementation by Bela Schaum, https://github.com/schaumb 8 | // The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669 9 | // 10 | 11 | #ifndef PFR_DETAIL_CORE_NAME_HPP 12 | #define PFR_DETAIL_CORE_NAME_HPP 13 | #pragma once 14 | 15 | #include 16 | 17 | // Each core_name provides `pfr::detail::get_name` and 18 | // `pfr::detail::tie_as_names_tuple` functions. 19 | // 20 | // The whole functional of extracting field's names is build on top of those 21 | // two functions. 22 | #if PFR_CORE_NAME_ENABLED 23 | #include 24 | #else 25 | #include 26 | #endif 27 | 28 | #endif // PFR_DETAIL_CORE_NAME_HPP 29 | 30 | -------------------------------------------------------------------------------- /modules/usage_test_mu1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // To compile manually use a command like the folowing: 7 | // clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp 8 | 9 | #include 10 | 11 | #include 12 | 13 | struct some_person { 14 | std::string name; 15 | unsigned birth_year; 16 | }; 17 | 18 | void mu1_act() { 19 | some_person val{"Edgar Allan Poe", 1809}; 20 | 21 | std::cout << pfr::get<0>(val) // No macro! 22 | << " was born in " << pfr::get<1>(val); // Works with any aggregate! 23 | 24 | std::cout << '\n' << pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809} 25 | std::cout << "\n." << pfr::get_name<0, some_person>() 26 | << '=' << val.name << '\n'; // Outputs: .name=Edgar Allan Poe 27 | } 28 | -------------------------------------------------------------------------------- /modules/boost_pfr.cppm: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // To compile manually use a command like the folowing: 7 | // clang++ -I ../include -std=c++20 --precompile -x c++-module pfr.cppm 8 | 9 | module; 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef PFR_USE_STD_MODULE 16 | import std; 17 | #else 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #endif 32 | 33 | #define PFR_INTERFACE_UNIT 34 | 35 | export module pfr; 36 | 37 | #ifdef __clang__ 38 | # pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" 39 | #endif 40 | 41 | #include 42 | 43 | -------------------------------------------------------------------------------- /modules/usage_sample.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // To compile manually use a command like the folowing: 7 | // clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp 8 | 9 | //[pfr_module_example 10 | #include 11 | #include 12 | #include 13 | 14 | import pfr; 15 | 16 | struct some_person { 17 | std::string name; 18 | unsigned birth_year; 19 | }; 20 | 21 | int main() { 22 | some_person val{"Edgar Allan Poe", 1809}; 23 | 24 | std::cout << pfr::get<0>(val) // No macro! 25 | << " was born in " << pfr::get<1>(val); // Works with any aggregate! 26 | 27 | std::cout << '\n' << pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809} 28 | std::cout << "\n." << pfr::get_name<0, some_person>() 29 | << '=' << val.name << '\n'; // Outputs: .name=Edgar Allan Poe 30 | } 31 | //] 32 | -------------------------------------------------------------------------------- /include/pfr/detail/config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // Copyright (c) 2022 Denis Mikhailov 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef PFR_DETAIL_CONFIG_HPP 8 | #define PFR_DETAIL_CONFIG_HPP 9 | #pragma once 10 | 11 | #include 12 | 13 | #if !PFR_ENABLED 14 | 15 | #error Boost.PFR library is not supported in your environment. \ 16 | Try one of the possible solutions: \ 17 | 1. try to take away an '-DPFR_ENABLED=0', if it exists \ 18 | 2. enable C++14; \ 19 | 3. enable C++17; \ 20 | 4. update your compiler; \ 21 | or disable this error by '-DPFR_ENABLED=1' if you really know what are you doing. 22 | 23 | #endif // !PFR_ENABLED 24 | 25 | #endif // PFR_DETAIL_CONFIG_HPP 26 | 27 | -------------------------------------------------------------------------------- /example/get.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2025 Antony Polukhin 2 | 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See the accompanying file LICENSE_1_0.txt 5 | // or a copy at .) 6 | 7 | //[pfr_example_get 8 | /*` 9 | The following example shows how to access structure fields by index using [funcref pfr::get]. 10 | 11 | Let's define some structure: 12 | */ 13 | #include 14 | 15 | struct foo { // defining structure 16 | int some_integer; 17 | char c; 18 | }; 19 | 20 | /*` 21 | We can access fields of that structure by index: 22 | */ 23 | foo f {777, '!'}; 24 | auto& r1 = pfr::get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer` 25 | auto& r2 = pfr::get<1>(f); // accessing field with index 1, returns reference to `foo::c` 26 | //] [/pfr_example_get] 27 | 28 | 29 | int main() { 30 | if (r1 != 777) return 1; 31 | if (r2 != '!') return 2; 32 | 33 | r1 = 42; 34 | r2 = 'A'; 35 | 36 | if (r1 != 42) return 3; 37 | if (r2 != 'A') return 4; 38 | if (f.some_integer != 42) return 5; 39 | if (f.c != 'A') return 6; 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /include/pfr/detail/rvalue_t.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_RVALUE_T_HPP 7 | #define PFR_DETAIL_RVALUE_T_HPP 8 | #pragma once 9 | 10 | #if !defined(PFR_INTERFACE_UNIT) 11 | #include 12 | #include // std::enable_if_t 13 | #endif 14 | 15 | // This header provides aliases rvalue_t and lvalue_t. 16 | // 17 | // Usage: template void foo(rvalue rvalue); 18 | // 19 | // Those are useful for 20 | // * better type safety - you can validate at compile time that only rvalue reference is passed into the function 21 | // * documentation and readability - rvalue_t is much better than T&&+SFINAE 22 | 23 | namespace pfr { namespace detail { 24 | 25 | /// Binds to rvalues only, no copying allowed. 26 | template ::value> 29 | #endif 30 | > 31 | using rvalue_t = T&&; 32 | 33 | /// Binds to mutable lvalues only 34 | 35 | }} // namespace pfr::detail 36 | 37 | #endif // PFR_DETAIL_RVALUE_T_HPP 38 | -------------------------------------------------------------------------------- /include/pfr/detail/stdarray.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Denis Mikhailov 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_STDARRAY_HPP 7 | #define PFR_DETAIL_STDARRAY_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #include 13 | 14 | #if !defined(PFR_INTERFACE_UNIT) 15 | #include 16 | #if PFR_CORE_NAME_ENABLED 17 | # include 18 | #endif 19 | #include // metaprogramming stuff 20 | #endif 21 | 22 | namespace pfr { namespace detail { 23 | 24 | #if PFR_CORE_NAME_ENABLED 25 | template 26 | constexpr auto make_stdarray_from_tietuple(const T& t, std::index_sequence) noexcept { 27 | return std::array{ 28 | pfr::detail::sequence_tuple::get(t)... 29 | }; 30 | } 31 | #else 32 | template 33 | constexpr auto make_stdarray_from_tietuple(const T&, std::index_sequence) noexcept { 34 | return nullptr; 35 | } 36 | #endif 37 | 38 | }} // namespace pfr::detail 39 | 40 | #endif // PFR_DETAIL_STDARRAY_HPP 41 | 42 | -------------------------------------------------------------------------------- /include/pfr/detail/unsafe_declval.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2025 Antony Polukhin. 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_UNSAFE_DECLVAL_HPP 7 | #define PFR_DETAIL_UNSAFE_DECLVAL_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #if !defined(PFR_INTERFACE_UNIT) 13 | #include 14 | #endif 15 | 16 | namespace pfr { namespace detail { 17 | 18 | // This function serves as a link-time assert. If linker requires it, then 19 | // `unsafe_declval()` is used at runtime. 20 | void report_if_you_see_link_error_with_this_function() noexcept; 21 | 22 | // For returning non default constructible types. Do NOT use at runtime! 23 | // 24 | // GCCs std::declval may not be used in potentionally evaluated contexts, 25 | // so we reinvent it. 26 | template 27 | constexpr T unsafe_declval() noexcept { 28 | report_if_you_see_link_error_with_this_function(); 29 | 30 | typename std::remove_reference::type* ptr = nullptr; 31 | ptr += 42; // suppresses 'null pointer dereference' warnings 32 | return static_cast(*ptr); 33 | } 34 | 35 | }} // namespace pfr::detail 36 | 37 | 38 | #endif // PFR_DETAIL_UNSAFE_DECLVAL_HPP 39 | 40 | -------------------------------------------------------------------------------- /example/get_name.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov. 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | 7 | // Initial implementation by Bela Schaum, https://github.com/schaumb 8 | // The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669 9 | // 10 | 11 | #include 12 | 13 | #if PFR_CORE_NAME_ENABLED && PFR_USE_CPP17 14 | //[pfr_example_get_name 15 | /*` 16 | Since C++20 it's possible to read name of a structure field by index using Boost.PFR library. 17 | The following example shows how to do it using [funcref pfr::get_name]. 18 | 19 | Let's define some structure: 20 | */ 21 | #include 22 | 23 | struct foo { // defining structure 24 | int some_integer; 25 | char c; 26 | }; 27 | 28 | /*` 29 | We can access field's names of that structure by index: 30 | */ 31 | constexpr std::string_view n1 = pfr::get_name<0, foo>(); // returns "some_integer" 32 | constexpr std::string_view n2 = pfr::get_name<1, foo>(); // returns "c" 33 | //] [/pfr_example_get_name] 34 | #endif 35 | 36 | int main() { 37 | #if PFR_CORE_NAME_ENABLED && PFR_USE_CPP17 38 | if (n1 != "some_integer") return 1; 39 | if (n2 != "c") return 2; 40 | #endif 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /include/pfr/detail/possible_reflectable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Denis Mikhailov 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP 7 | #define PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | #if !defined(PFR_INTERFACE_UNIT) 14 | #include // for std::is_aggregate 15 | #endif 16 | 17 | namespace pfr { namespace detail { 18 | 19 | ///////////////////// Returns false when the type exactly wasn't be reflectable 20 | template 21 | constexpr decltype(is_reflectable::value) possible_reflectable(long) noexcept { 22 | return is_reflectable::value; 23 | } 24 | 25 | #if PFR_ENABLE_IMPLICIT_REFLECTION 26 | 27 | template 28 | constexpr bool possible_reflectable(int) noexcept { 29 | # if defined(__cpp_lib_is_aggregate) 30 | using type = std::remove_cv_t; 31 | return std::is_aggregate(); 32 | # else 33 | return true; 34 | # endif 35 | } 36 | 37 | #else 38 | 39 | template 40 | constexpr bool possible_reflectable(int) noexcept { 41 | // negative answer here won't change behaviour in PFR-dependent libraries(like Fusion) 42 | return false; 43 | } 44 | 45 | #endif 46 | 47 | }} // namespace pfr::detail 48 | 49 | #endif // PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP 50 | 51 | 52 | -------------------------------------------------------------------------------- /include/pfr/detail/tie_from_structure_tuple.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Adam Butcher, Antony Polukhin 2 | // Copyright (c) 2019-2025 Antony Polukhin 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP 8 | #define PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP 9 | #pragma once 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #if !defined(PFR_INTERFACE_UNIT) 20 | #include 21 | #endif 22 | 23 | namespace pfr { namespace detail { 24 | 25 | /// \brief A `std::tuple` capable of de-structuring assignment used to support 26 | /// a tie of multiple lvalue references to fields of an aggregate T. 27 | /// 28 | /// \sa pfr::tie_from_structure 29 | template 30 | struct tie_from_structure_tuple : std::tuple { 31 | using base = std::tuple; 32 | using base::base; 33 | 34 | template 35 | constexpr tie_from_structure_tuple& operator= (T const& t) { 36 | base::operator=( 37 | detail::make_stdtiedtuple_from_tietuple( 38 | detail::tie_as_tuple(t), 39 | detail::make_index_sequence>())); 40 | return *this; 41 | } 42 | }; 43 | 44 | }} // namespace pfr::detail 45 | 46 | #endif // PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP 47 | -------------------------------------------------------------------------------- /include/pfr/detail/core_name14_disabled.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov. 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | 7 | // Initial implementation by Bela Schaum, https://github.com/schaumb 8 | // The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669 9 | // 10 | 11 | #ifndef PFR_DETAIL_CORE_NAME14_DISABLED_HPP 12 | #define PFR_DETAIL_CORE_NAME14_DISABLED_HPP 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | namespace pfr { namespace detail { 19 | 20 | template 21 | constexpr auto get_name() noexcept { 22 | static_assert( 23 | sizeof(T) && false, 24 | "====================> Boost.PFR: Field's names extracting functionality requires C++20." 25 | ); 26 | 27 | return nullptr; 28 | } 29 | 30 | template 31 | constexpr auto tie_as_names_tuple() noexcept { 32 | static_assert( 33 | sizeof(T) && false, 34 | "====================> Boost.PFR: Field's names extracting functionality requires C++20." 35 | ); 36 | 37 | return detail::sequence_tuple::make_sequence_tuple(); 38 | } 39 | 40 | 41 | template 42 | constexpr void for_each_field_with_name(T&& /* value */, F&& /* func */) { 43 | static_assert( 44 | sizeof(T) && false, 45 | "====================> Boost.PFR: Field's names extracting functionality requires C++20." 46 | ); 47 | } 48 | 49 | }} // namespace pfr::detail 50 | 51 | #endif // PFR_DETAIL_CORE_NAME14_DISABLED_HPP 52 | 53 | -------------------------------------------------------------------------------- /include/pfr/detail/for_each_field.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_FOR_EACH_FIELD_HPP 7 | #define PFR_DETAIL_FOR_EACH_FIELD_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #if !defined(PFR_INTERFACE_UNIT) 18 | #include // metaprogramming stuff 19 | #endif 20 | 21 | namespace pfr { namespace detail { 22 | 23 | template 24 | constexpr void for_each_field(T&& value, F&& func) { 25 | constexpr std::size_t fields_count_val = pfr::detail::fields_count>(); 26 | 27 | ::pfr::detail::for_each_field_dispatcher( 28 | value, 29 | [f = std::forward(func)](auto&& t) mutable { 30 | // MSVC related workaround. Its lambdas do not capture constexprs. 31 | constexpr std::size_t fields_count_val_in_lambda 32 | = pfr::detail::fields_count>(); 33 | 34 | ::pfr::detail::for_each_field_impl( 35 | t, 36 | std::forward(f), 37 | detail::make_index_sequence{}, 38 | std::is_rvalue_reference{} 39 | ); 40 | }, 41 | detail::make_index_sequence{} 42 | ); 43 | } 44 | 45 | }} // namespace pfr::detail 46 | 47 | 48 | #endif // PFR_DETAIL_FOR_EACH_FIELD_HPP 49 | -------------------------------------------------------------------------------- /include/pfr/tuple_size.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | 7 | #ifndef PFR_TUPLE_SIZE_HPP 8 | #define PFR_TUPLE_SIZE_HPP 9 | #pragma once 10 | 11 | #include 12 | 13 | #if !defined(PFR_USE_MODULES) || defined(PFR_INTERFACE_UNIT) 14 | 15 | #include 16 | #include 17 | 18 | #if !defined(PFR_INTERFACE_UNIT) 19 | #include 20 | #include // metaprogramming stuff 21 | #endif 22 | 23 | /// \file pfr/tuple_size.hpp 24 | /// Contains tuple-like interfaces to get fields count \forcedlink{tuple_size}, \forcedlink{tuple_size_v}. 25 | /// 26 | /// \b Synopsis: 27 | namespace pfr { 28 | 29 | PFR_BEGIN_MODULE_EXPORT 30 | 31 | /// Has a static const member variable `value` that contains fields count in a T. 32 | /// Works for any T that satisfies \aggregate. 33 | /// 34 | /// \b Example: 35 | /// \code 36 | /// std::array::value > a; 37 | /// \endcode 38 | template 39 | using tuple_size = detail::size_t_< pfr::detail::fields_count() >; 40 | 41 | 42 | /// `tuple_size_v` is a template variable that contains fields count in a T and 43 | /// works for any T that satisfies \aggregate. 44 | /// 45 | /// \b Example: 46 | /// \code 47 | /// std::array > a; 48 | /// \endcode 49 | template 50 | constexpr std::size_t tuple_size_v = tuple_size::value; 51 | 52 | PFR_END_MODULE_EXPORT 53 | 54 | } // namespace pfr 55 | 56 | #endif // #if defined(PFR_USE_MODULES) && !defined(PFR_INTERFACE_UNIT) 57 | 58 | #endif // PFR_TUPLE_SIZE_HPP 59 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Peter Dimov 2 | # Copyright (c) 2016-2025 Antony Polukhin 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # https://www.boost.org/LICENSE_1_0.txt 6 | 7 | cmake_minimum_required(VERSION 3.5...3.31) 8 | 9 | project(pfr VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) 10 | 11 | if (PFR_USE_MODULES) 12 | add_library(pfr) 13 | target_sources(pfr PUBLIC 14 | FILE_SET modules_public TYPE CXX_MODULES FILES modules/boost_pfr.cppm 15 | ) 16 | 17 | target_compile_features(pfr PUBLIC cxx_std_20) 18 | target_compile_definitions(pfr PUBLIC PFR_USE_MODULES) 19 | if (CMAKE_CXX_COMPILER_IMPORT_STD) 20 | target_compile_definitions(pfr PRIVATE PFR_USE_STD_MODULE) 21 | message(STATUS "Using `import std;`") 22 | else() 23 | message(STATUS "`import std;` is not available") 24 | endif() 25 | target_include_directories(pfr PUBLIC include) 26 | else() 27 | add_library(pfr INTERFACE) 28 | target_include_directories(pfr INTERFACE include) 29 | endif() 30 | 31 | add_library(pfr::pfr ALIAS pfr) 32 | 33 | enable_testing() 34 | if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") 35 | add_subdirectory(test) 36 | endif() 37 | 38 | if (PFR_USE_MODULES AND BUILD_TESTING) 39 | add_executable(pfr_module_usage modules/usage_sample.cpp) 40 | target_link_libraries(pfr_module_usage PRIVATE pfr::pfr) 41 | add_test(NAME pfr_module_usage COMMAND pfr_module_usage) 42 | 43 | # Make sure that mixing includes and imports is fine for different TU 44 | add_executable(pfr_module_usage_mu modules/usage_test_mu1.cpp modules/usage_test_mu2.cpp) 45 | target_link_libraries(pfr_module_usage_mu PRIVATE pfr::pfr) 46 | add_test(NAME pfr_module_usage_mu COMMAND pfr_module_usage_mu) 47 | endif() 48 | 49 | -------------------------------------------------------------------------------- /include/pfr/detail/fake_object.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov. 2 | // Copyright (c) 2024-2025 Antony Polukhin 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | 8 | // Initial implementation by Bela Schaum, https://github.com/schaumb 9 | // The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669 10 | // 11 | 12 | #ifndef PFR_DETAIL_FAKE_OBJECT_HPP 13 | #define PFR_DETAIL_FAKE_OBJECT_HPP 14 | #pragma once 15 | 16 | #include 17 | 18 | #ifdef __clang__ 19 | # pragma clang diagnostic push 20 | # pragma clang diagnostic ignored "-Wundefined-internal" 21 | # pragma clang diagnostic ignored "-Wundefined-var-template" 22 | #endif 23 | 24 | namespace pfr { namespace detail { 25 | 26 | // This class has external linkage while T has not sure. 27 | template 28 | struct wrapper { 29 | const T value; 30 | }; 31 | 32 | // This variable servers as a link-time assert. 33 | // If linker requires it, then `fake_object()` is used at runtime. 34 | template 35 | extern const wrapper do_not_use_PFR_with_local_types; 36 | 37 | // For returning non default constructible types, it's exclusively used in member name retrieval. 38 | // 39 | // Neither std::declval nor pfr::detail::unsafe_declval are usable there. 40 | // This takes advantage of C++20 features, while pfr::detail::unsafe_declval works 41 | // with the former standards. 42 | template 43 | constexpr const T& fake_object() noexcept { 44 | return do_not_use_PFR_with_local_types.value; 45 | } 46 | 47 | }} // namespace pfr::detail 48 | 49 | #ifdef __clang__ 50 | # pragma clang diagnostic pop 51 | #endif 52 | 53 | #endif // PFR_DETAIL_FAKE_OBJECT_HPP 54 | 55 | -------------------------------------------------------------------------------- /include/pfr/detail/stdtuple.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_STDTUPLE_HPP 7 | #define PFR_DETAIL_STDTUPLE_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #include 13 | 14 | #if !defined(PFR_INTERFACE_UNIT) 15 | #include // metaprogramming stuff 16 | #include 17 | #endif 18 | 19 | namespace pfr { namespace detail { 20 | 21 | template 22 | constexpr auto make_stdtuple_from_tietuple(const T& t, std::index_sequence) { 23 | (void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter` 24 | return std::make_tuple( 25 | pfr::detail::sequence_tuple::get(t)... 26 | ); 27 | } 28 | 29 | template 30 | constexpr auto make_stdtiedtuple_from_tietuple(const T& t, std::index_sequence) noexcept { 31 | (void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter` 32 | return std::tie( 33 | pfr::detail::sequence_tuple::get(t)... 34 | ); 35 | } 36 | 37 | template 38 | constexpr auto make_conststdtiedtuple_from_tietuple(const T& t, std::index_sequence) noexcept { 39 | (void)t; // workaround for MSVC 14.1 `warning C4100: 't': unreferenced formal parameter` 40 | return std::tuple< 41 | std::add_lvalue_reference_t(t))> 43 | >>... 44 | >( 45 | pfr::detail::sequence_tuple::get(t)... 46 | ); 47 | } 48 | 49 | }} // namespace pfr::detail 50 | 51 | #endif // PFR_DETAIL_STDTUPLE_HPP 52 | -------------------------------------------------------------------------------- /include/pfr/detail/size_array.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_SIZE_ARRAY_HPP 7 | #define PFR_DETAIL_SIZE_ARRAY_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #if !defined(PFR_INTERFACE_UNIT) 13 | #include 14 | #endif 15 | 16 | namespace pfr { namespace detail { 17 | 18 | ///////////////////// Array that has the constexpr 19 | template 20 | struct size_array { // libc++ misses constexpr on operator[] 21 | typedef std::size_t type; 22 | std::size_t data[N]; 23 | 24 | static constexpr std::size_t size() noexcept { return N; } 25 | 26 | constexpr std::size_t count_nonzeros() const noexcept { 27 | std::size_t count = 0; 28 | for (std::size_t i = 0; i < size(); ++i) { 29 | if (data[i]) { 30 | ++ count; 31 | } 32 | } 33 | return count; 34 | } 35 | 36 | constexpr std::size_t count_from_opening_till_matching_parenthis_seq(std::size_t from, std::size_t opening_parenthis, std::size_t closing_parenthis) const noexcept { 37 | if (data[from] != opening_parenthis) { 38 | return 0; 39 | } 40 | std::size_t unclosed_parnthesis = 0; 41 | std::size_t count = 0; 42 | for (; ; ++from) { 43 | if (data[from] == opening_parenthis) { 44 | ++ unclosed_parnthesis; 45 | } else if (data[from] == closing_parenthis) { 46 | -- unclosed_parnthesis; 47 | } 48 | ++ count; 49 | 50 | if (unclosed_parnthesis == 0) { 51 | return count; 52 | } 53 | } 54 | 55 | return count; 56 | } 57 | }; 58 | 59 | template <> 60 | struct size_array<0> { // libc++ misses constexpr on operator[] 61 | typedef std::size_t type; 62 | std::size_t data[1]; 63 | 64 | static constexpr std::size_t size() noexcept { return 0; } 65 | 66 | constexpr std::size_t count_nonzeros() const noexcept { 67 | return 0; 68 | } 69 | }; 70 | 71 | template 72 | constexpr std::size_t get(const size_array& a) noexcept { 73 | static_assert(I < N, "====================> Boost.PFR: Array index out of bounds"); 74 | return a.data[I]; 75 | } 76 | 77 | 78 | 79 | }} // namespace pfr::detail 80 | 81 | #endif // PFR_DETAIL_SIZE_ARRAY_HPP 82 | -------------------------------------------------------------------------------- /include/pfr/detail/for_each_field_impl.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP 7 | #define PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #if !defined(PFR_INTERFACE_UNIT) 16 | #include // metaprogramming stuff 17 | #endif 18 | 19 | namespace pfr { namespace detail { 20 | 21 | template 22 | using size_t_ = std::integral_constant; 23 | 24 | template ()(std::declval(), I{}))> 25 | constexpr void for_each_field_impl_apply(T&& v, F&& f, I i, long) { 26 | std::forward(f)(std::forward(v), i); 27 | } 28 | 29 | template 30 | constexpr void for_each_field_impl_apply(T&& v, F&& f, I /*i*/, int) { 31 | std::forward(f)(std::forward(v)); 32 | } 33 | 34 | #if !defined(__cpp_fold_expressions) || __cpp_fold_expressions < 201603 35 | template 36 | constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence, std::false_type /*move_values*/) { 37 | const int v[] = {0, ( 38 | detail::for_each_field_impl_apply(sequence_tuple::get(t), std::forward(f), size_t_{}, 1L), 39 | 0 40 | )...}; 41 | (void)v; 42 | } 43 | 44 | 45 | template 46 | constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence, std::true_type /*move_values*/) { 47 | const int v[] = {0, ( 48 | detail::for_each_field_impl_apply(sequence_tuple::get(std::move(t)), std::forward(f), size_t_{}, 1L), 49 | 0 50 | )...}; 51 | (void)v; 52 | } 53 | #else 54 | template 55 | constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence, std::false_type /*move_values*/) { 56 | (detail::for_each_field_impl_apply(sequence_tuple::get(t), std::forward(f), size_t_{}, 1L), ...); 57 | } 58 | 59 | template 60 | constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence, std::true_type /*move_values*/) { 61 | (detail::for_each_field_impl_apply(sequence_tuple::get(std::move(t)), std::forward(f), size_t_{}, 1L), ...); 62 | } 63 | #endif 64 | 65 | }} // namespace pfr::detail 66 | 67 | 68 | #endif // PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP 69 | -------------------------------------------------------------------------------- /include/pfr/detail/io.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_IO_HPP 7 | #define PFR_DETAIL_IO_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #include 13 | 14 | #if !defined(PFR_INTERFACE_UNIT) 15 | #include // stream operators 16 | #include 17 | 18 | #if defined(__has_include) 19 | # if __has_include() && PFR_USE_CPP17 20 | # include 21 | # endif 22 | #endif 23 | 24 | #endif 25 | 26 | namespace pfr { namespace detail { 27 | 28 | inline auto quoted_helper(const std::string& s) noexcept { 29 | return std::quoted(s); 30 | } 31 | 32 | #if defined(__has_include) 33 | # if __has_include() && PFR_USE_CPP17 34 | template 35 | inline auto quoted_helper(std::basic_string_view s) noexcept { 36 | return std::quoted(s); 37 | } 38 | # endif 39 | #endif 40 | 41 | inline auto quoted_helper(std::string& s) noexcept { 42 | return std::quoted(s); 43 | } 44 | 45 | template 46 | inline decltype(auto) quoted_helper(T&& v) noexcept { 47 | return std::forward(v); 48 | } 49 | 50 | template 51 | struct print_impl { 52 | template 53 | static void print (Stream& out, const T& value) { 54 | if (!!I) out << ", "; 55 | out << detail::quoted_helper(pfr::detail::sequence_tuple::get(value)); 56 | print_impl::print(out, value); 57 | } 58 | }; 59 | 60 | template 61 | struct print_impl { 62 | template static void print (Stream&, const T&) noexcept {} 63 | }; 64 | 65 | 66 | template 67 | struct read_impl { 68 | template 69 | static void read (Stream& in, const T& value) { 70 | char ignore = {}; 71 | if (!!I) { 72 | in >> ignore; 73 | if (ignore != ',') in.setstate(Stream::failbit); 74 | in >> ignore; 75 | if (ignore != ' ') in.setstate(Stream::failbit); 76 | } 77 | in >> detail::quoted_helper( pfr::detail::sequence_tuple::get(value) ); 78 | read_impl::read(in, value); 79 | } 80 | }; 81 | 82 | template 83 | struct read_impl { 84 | template static void read (Stream&, const T&) {} 85 | }; 86 | 87 | }} // namespace pfr::detail 88 | 89 | #endif // PFR_DETAIL_IO_HPP 90 | -------------------------------------------------------------------------------- /example/sample_printing.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2025 Antony Polukhin 2 | 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See the accompanying file LICENSE_1_0.txt 5 | // or a copy at .) 6 | 7 | //[pfr_sample_printing 8 | /*` 9 | The following example shows how to write your own io-manipulator for printing: 10 | */ 11 | #include 12 | #include 13 | 14 | namespace my_ns { 15 | 16 | /// Usage: 17 | /// struct foo {std::uint8_t a, b;}; 18 | /// ... 19 | /// std::cout << my_ns::my_io(foo{42, 22}); 20 | /// 21 | /// Output: 42, 22 22 | template 23 | auto my_io(const T& value); 24 | 25 | namespace detail { 26 | // Helpers to print individual values 27 | template 28 | void print_each(std::ostream& out, const T& v) { out << v; } 29 | void print_each(std::ostream& out, std::uint8_t v) { out << static_cast(v); } 30 | void print_each(std::ostream& out, std::int8_t v) { out << static_cast(v); } 31 | 32 | // Structure to keep a reference to value, that will be ostreamed lower 33 | template 34 | struct io_reference { 35 | const T& value; 36 | }; 37 | 38 | // Output each field of io_reference::value 39 | template 40 | std::ostream& operator<<(std::ostream& out, io_reference&& x) { 41 | const char* sep = ""; 42 | 43 | pfr::for_each_field(x.value, [&](const auto& v) { 44 | out << std::exchange(sep, ", "); 45 | detail::print_each(out, v); 46 | }); 47 | return out; 48 | } 49 | } 50 | 51 | // Definition: 52 | template 53 | auto my_io(const T& value) { 54 | return detail::io_reference{value}; 55 | } 56 | 57 | } // namespace my_ns 58 | //] [/pfr_sample_printing] 59 | 60 | 61 | #include 62 | #include 63 | 64 | int main() { 65 | struct foo {std::uint8_t a, b;}; 66 | 67 | std::ostringstream oss; 68 | oss << my_ns::my_io(foo{42, 22}); 69 | 70 | if (oss.str() != "42, 22") { 71 | return 1; 72 | } 73 | 74 | struct two_big_strings { 75 | std::string first; 76 | std::string second; 77 | }; 78 | 79 | #if PFR_USE_CPP17 || PFR_USE_LOOPHOLE 80 | const char* huge_string = "Some huge string that should not fit into std::string SSO." 81 | "And by 'huge' I mean really HUGE string with multiple statements and a lot of periods........." 82 | ; 83 | 84 | oss.str({}); 85 | oss << my_ns::my_io(two_big_strings{ 86 | huge_string, huge_string 87 | }); 88 | 89 | if (oss.str() != huge_string + std::string(", ") + huge_string) { 90 | return 2; 91 | } 92 | #endif 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /doc/Jamfile.v2: -------------------------------------------------------------------------------- 1 | # Copyright Antony Polukhin 2016-2019. 2 | # Use, modification, and distribution are 3 | # subject to the Boost Software License, Version 1.0. (See accompanying 4 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | using quickbook ; 7 | using boostbook ; 8 | using doxygen ; 9 | using xsltproc ; 10 | 11 | import set ; 12 | import doxygen ; 13 | import xsltproc ; 14 | import notfile ; 15 | import path ; 16 | 17 | project pfr/doc ; 18 | 19 | # 20 | # Common params for doxygen 21 | # 22 | 23 | local doxygen_params = 24 | EXTRACT_ALL=NO 25 | HIDE_UNDOC_MEMBERS=YES 26 | EXTRACT_PRIVATE=NO 27 | ENABLE_PREPROCESSING=YES 28 | EXPAND_ONLY_PREDEF=YES 29 | MACRO_EXPANSION=YES 30 | INLINE_SIMPLE_STRUCTS=YES 31 | SORT_MEMBER_DOCS=NO 32 | "ALIASES= \\ 33 | \"forcedlink{1}=\\xmlonly\\endxmlonly pfr::\\1\\xmlonly\\endxmlonly\" \\ 34 | \"podops=\\b See \\b Also : \\xmlonly\\endxmlonly 'Three ways of getting operators' \\xmlonly\\endxmlonly\" \\ 35 | \"fnrefl=\\b See \\b Also : \\xmlonly\\endxmlonly 'Reflection of field names' \\xmlonly\\endxmlonly\" \\ 36 | \"customio=\\b See \\b Also : \\xmlonly\\endxmlonly 'Custom printing of aggregates' \\xmlonly\\endxmlonly for info on how to implement your own manipulator with custom format.\" \\ 37 | \"aggregate=\\xmlonly\\endxmlonly simple aggregate \\xmlonly\\endxmlonly\" \\ 38 | " 39 | "PREDEFINED= \\ 40 | \"PFR_DOXYGEN_INVOKED=1\" \\ 41 | " 42 | ; 43 | 44 | doxygen autodoc_pfr 45 | : 46 | [ glob ../include/pfr.hpp ] 47 | [ glob ../include/pfr/*.hpp ] 48 | : 49 | $(doxygen_params) 50 | "boost.doxygen.reftitle=Reference Section of PFR" 51 | ; 52 | 53 | boostbook pfr-doc 54 | : 55 | pfr.qbk 56 | : 57 | autodoc_pfr 58 | boost.root=https://www.boost.org/doc/libs/1_81_0 59 | #boost.root=../../../. 60 | html.stylesheet=../../../../doc/src/boostbook.css 61 | ; 62 | 63 | ############################################################################### 64 | alias boostdoc 65 | : pfr-doc/docbook 66 | : 67 | : 68 | : ; 69 | explicit boostdoc ; 70 | alias boostrelease ; 71 | explicit boostrelease ; 72 | 73 | -------------------------------------------------------------------------------- /include/pfr/detail/core17.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | 7 | #ifndef PFR_DETAIL_CORE17_HPP 8 | #define PFR_DETAIL_CORE17_HPP 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace pfr { namespace detail { 17 | 18 | #ifndef _MSC_VER // MSVC fails to compile the following code, but compiles the structured bindings in core17_generated.hpp 19 | struct do_not_define_std_tuple_size_for_me { 20 | bool test1 = true; 21 | }; 22 | 23 | template 24 | constexpr bool do_structured_bindings_work() noexcept { // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN pfr/detail/core17.hpp FILE: 25 | T val{}; 26 | auto& [a] = val; // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN pfr/detail/core17.hpp FILE: 27 | 28 | /**************************************************************************** 29 | * 30 | * It looks like your compiler or Standard Library can not handle C++17 31 | * structured bindings. 32 | * 33 | * Workaround: Define PFR_USE_CPP17 to 0 34 | * It will disable the C++17 features for Boost.PFR library. 35 | * 36 | * Sorry for the inconvenience caused. 37 | * 38 | ****************************************************************************/ 39 | 40 | return a; 41 | } 42 | 43 | static_assert( 44 | do_structured_bindings_work(), 45 | "====================> Boost.PFR: Your compiler can not handle C++17 structured bindings. Read the above comments for workarounds." 46 | ); 47 | #endif // #ifndef _MSC_VER 48 | 49 | template 50 | constexpr auto tie_as_tuple(T& val) noexcept { 51 | static_assert( 52 | !std::is_union::value, 53 | "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." 54 | ); 55 | typedef size_t_()> fields_count_tag; 56 | return pfr::detail::tie_as_tuple(val, fields_count_tag{}); 57 | } 58 | 59 | template 60 | constexpr void for_each_field_dispatcher(T& t, F&& f, std::index_sequence) { 61 | static_assert( 62 | !std::is_union::value, 63 | "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." 64 | ); 65 | std::forward(f)( 66 | detail::tie_as_tuple(t) 67 | ); 68 | } 69 | 70 | }} // namespace pfr::detail 71 | 72 | #endif // PFR_DETAIL_CORE17_HPP 73 | -------------------------------------------------------------------------------- /include/pfr/detail/make_integer_sequence.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Sergei Fedorov 2 | // Copyright (c) 2019-2025 Antony Polukhin 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef PFR_DETAIL_MAKE_INTEGER_SEQUENCE_HPP 8 | #define PFR_DETAIL_MAKE_INTEGER_SEQUENCE_HPP 9 | #pragma once 10 | 11 | #include 12 | 13 | #if !defined(PFR_INTERFACE_UNIT) 14 | #include 15 | #include 16 | #include 17 | #endif 18 | 19 | namespace pfr { namespace detail { 20 | 21 | #if PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == 0 22 | 23 | #ifdef __has_builtin 24 | # if __has_builtin(__make_integer_seq) 25 | # define PFR_USE_MAKE_INTEGER_SEQ_BUILTIN 26 | # endif 27 | #endif 28 | 29 | #ifdef PFR_USE_MAKE_INTEGER_SEQ_BUILTIN 30 | 31 | using std::integer_sequence; 32 | 33 | // Clang unable to use namespace qualified std::integer_sequence in __make_integer_seq. 34 | template 35 | using make_integer_sequence = __make_integer_seq; 36 | 37 | #undef PFR_USE_MAKE_INTEGER_SEQ_BUILTIN 38 | 39 | #else 40 | 41 | template 42 | struct join_sequences; 43 | 44 | template 45 | struct join_sequences, std::integer_sequence> { 46 | using type = std::integer_sequence; 47 | }; 48 | 49 | template 50 | struct build_sequence_impl { 51 | static_assert(Min < Max, "Start of range must be less than its end"); 52 | static constexpr T size = Max - Min; 53 | using type = typename join_sequences< 54 | typename build_sequence_impl::type, 55 | typename build_sequence_impl::type 56 | >::type; 57 | }; 58 | 59 | template 60 | struct build_sequence_impl { 61 | using type = std::integer_sequence; 62 | }; 63 | 64 | template 65 | struct make_integer_sequence_impl : build_sequence_impl {}; 66 | 67 | template 68 | struct make_integer_sequence_impl { 69 | using type = std::integer_sequence; 70 | }; 71 | 72 | template 73 | using make_integer_sequence = typename make_integer_sequence_impl::type; 74 | 75 | #endif // !defined PFR_USE_MAKE_INTEGER_SEQ_BUILTIN 76 | #else // PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == 1 77 | 78 | template 79 | using make_integer_sequence = std::make_integer_sequence; 80 | 81 | #endif // PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == 1 82 | 83 | template 84 | using make_index_sequence = make_integer_sequence; 85 | 86 | template 87 | using index_sequence_for = make_index_sequence; 88 | 89 | }} // namespace pfr::detail 90 | 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /include/pfr/traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Denis Mikhailov 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_TRAITS_HPP 7 | #define PFR_TRAITS_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #if !defined(PFR_USE_MODULES) || defined(PFR_INTERFACE_UNIT) 13 | 14 | #include 15 | 16 | #if !defined(PFR_INTERFACE_UNIT) 17 | #include 18 | #endif 19 | 20 | /// \file pfr/traits.hpp 21 | /// Contains traits \forcedlink{is_reflectable} and \forcedlink{is_implicitly_reflectable} for detecting an ability to reflect type. 22 | /// 23 | /// \b Synopsis: 24 | 25 | namespace pfr { 26 | 27 | PFR_BEGIN_MODULE_EXPORT 28 | 29 | /// Has a static const member variable `value` when it is known that type T can or can't be reflected using Boost.PFR; otherwise, there is no member variable. 30 | /// Every user may (and in some difficult cases - should) specialize is_reflectable on his own. 31 | /// 32 | /// \b Example: 33 | /// \code 34 | /// namespace pfr { 35 | /// template struct is_reflectable : std::false_type {}; // 'A' won't be interpreted as reflectable everywhere 36 | /// template<> struct is_reflectable : std::false_type {}; // 'B' won't be interpreted as reflectable in only Boost Fusion 37 | /// }} 38 | /// \endcode 39 | /// \note is_reflectable affects is_implicitly_reflectable, the decision made by is_reflectable is used by is_implicitly_reflectable. 40 | template 41 | struct is_reflectable { /* does not have 'value' because value is unknown */ }; 42 | 43 | // these specs can't be inherited from 'std::integral_constant< bool, pfr::is_reflectable::value >', 44 | // because it will break the sfinae-friendliness 45 | template 46 | struct is_reflectable : pfr::is_reflectable {}; 47 | 48 | template 49 | struct is_reflectable : pfr::is_reflectable {}; 50 | 51 | template 52 | struct is_reflectable : pfr::is_reflectable {}; 53 | 54 | /// Checks the input type for the potential to be reflected. 55 | /// Specialize is_reflectable if you disagree with is_implicitly_reflectable's default decision. 56 | template 57 | using is_implicitly_reflectable = std::integral_constant< bool, pfr::detail::possible_reflectable(1L) >; 58 | 59 | /// Checks the input type for the potential to be reflected. 60 | /// Specialize is_reflectable if you disagree with is_implicitly_reflectable_v's default decision. 61 | template 62 | constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable::value; 63 | 64 | PFR_END_MODULE_EXPORT 65 | 66 | } // namespace pfr 67 | 68 | #endif // #if !defined(PFR_USE_MODULES) || defined(PFR_INTERFACE_UNIT) 69 | 70 | #endif // PFR_TRAITS_HPP 71 | 72 | -------------------------------------------------------------------------------- /include/pfr/detail/detectors.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2025 Antony Polukhin 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef PFR_DETAIL_DETECTORS_HPP 7 | #define PFR_DETAIL_DETECTORS_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #if !defined(PFR_INTERFACE_UNIT) 13 | #include 14 | #include 15 | #endif 16 | 17 | namespace pfr { namespace detail { 18 | ///////////////////// `value` is true if Detector does not compile (SFINAE) 19 | struct can_not_apply{}; 20 | 21 | template