├── CMakeLists.txt ├── LICENSE_1_0.txt ├── README.md ├── build.jam ├── doc ├── Jamfile.v2 └── pfr.qbk ├── example ├── get.cpp ├── get_name.cpp ├── motivating_example0.cpp ├── quick_examples.cpp └── sample_printing.cpp ├── include ├── pfr.hpp └── pfr │ ├── config.hpp │ ├── core.hpp │ ├── core_name.hpp │ ├── detail │ ├── config.hpp │ ├── core.hpp │ ├── core14_classic.hpp │ ├── core14_loophole.hpp │ ├── core17.hpp │ ├── core17_generated.hpp │ ├── core_name.hpp │ ├── core_name14_disabled.hpp │ ├── core_name20_static.hpp │ ├── detectors.hpp │ ├── fake_object.hpp │ ├── fields_count.hpp │ ├── for_each_field.hpp │ ├── for_each_field_impl.hpp │ ├── functional.hpp │ ├── io.hpp │ ├── make_flat_tuple_of_references.hpp │ ├── make_integer_sequence.hpp │ ├── offset_based_getter.hpp │ ├── possible_reflectable.hpp │ ├── rvalue_t.hpp │ ├── sequence_tuple.hpp │ ├── size_array.hpp │ ├── size_t_.hpp │ ├── stdarray.hpp │ ├── stdtuple.hpp │ ├── tie_from_structure_tuple.hpp │ └── unsafe_declval.hpp │ ├── functions_for.hpp │ ├── functors.hpp │ ├── io.hpp │ ├── io_fields.hpp │ ├── ops.hpp │ ├── ops_fields.hpp │ ├── traits.hpp │ ├── traits_fwd.hpp │ └── tuple_size.hpp ├── index.html ├── misc ├── generate_cpp17.py └── generate_fields_names_big.cpp.py └── module ├── CMakeLists.txt ├── pfr.cppm ├── usage_sample.cpp ├── usage_test_mu1.cpp └── usage_test_mu2.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Peter Dimov 2 | # Copyright (c) 2016-2024 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.16) 8 | 9 | project(boost_pfr VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) 10 | 11 | add_library(boost_pfr INTERFACE) 12 | add_library(Boost::pfr ALIAS boost_pfr) 13 | 14 | target_include_directories(boost_pfr INTERFACE include) 15 | 16 | if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28.0" AND BUILD_MODULE) 17 | add_subdirectory(module) 18 | endif() 19 | 20 | if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") 21 | add_subdirectory(test) 22 | endif() 23 | 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [PFR](https://apolukhin.github.io/pfr_non_boost/) 2 | 3 | This is a C++14 library for very basic reflection that gives you access to structure elements by index and provides other `std::tuple` like methods for user defined types without any macro or boilerplate code. 4 | 5 | [Boost.PFR](https://boost.org/libs/pfr) is a part of the [Boost C++ Libraries](https://github.com/boostorg). However, Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder from the github into your project, and the library will work fine. 6 | 7 | For a version of the library without `boost::` namespace see [PFR](https://github.com/apolukhin/pfr_non_boost). 8 | 9 | ### Test results 10 | 11 | Branches | Build | Tests coverage | More info 12 | ----------------|-------------- | -------------- |----------- 13 | Develop: | [![CI](https://github.com/boostorg/pfr/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/pfr/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/0mavmnkdmltcdmqa/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/pfr/branch/develop) | [![Coverage Status](https://coveralls.io/repos/github/apolukhin/magic_get/badge.png?branch=develop)](https://coveralls.io/github/apolukhin/magic_get?branch=develop) | [details...](https://www.boost.org/development/tests/develop/developer/pfr.html) 14 | Master: | [![CI](https://github.com/boostorg/pfr/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/pfr/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/0mavmnkdmltcdmqa/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/pfr/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/apolukhin/magic_get/badge.png?branch=master)](https://coveralls.io/github/apolukhin/magic_get?branch=master) | [details...](https://www.boost.org/development/tests/master/developer/pfr.html) 15 | 16 | [Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/boost_pfr.html) 17 | 18 | ### Motivating Example #0 19 | ```c++ 20 | #include 21 | #include 22 | #include 23 | 24 | #include "pfr.hpp" 25 | 26 | struct some_person { 27 | std::string name; 28 | unsigned birth_year; 29 | }; 30 | 31 | int main(int argc, const char* argv[]) { 32 | some_person val{"Edgar Allan Poe", 1809}; 33 | 34 | std::cout << pfr::get<0>(val) // No macro! 35 | << " was born in " << pfr::get<1>(val); // Works with any aggregate initializables! 36 | 37 | if (argc > 1) { 38 | std::ofstream ofs(argv[1]); 39 | ofs << pfr::io(val); // File now contains: {"Edgar Allan Poe", 1809} 40 | } 41 | } 42 | ``` 43 | Outputs: 44 | ``` 45 | Edgar Allan Poe was born in 1809 46 | ``` 47 | 48 | [Run the above sample](https://godbolt.org/z/PfYsWKb7v) 49 | 50 | 51 | ### Motivating Example #1 52 | ```c++ 53 | #include 54 | #include "pfr.hpp" 55 | 56 | struct my_struct { // no ostream operator defined! 57 | int i; 58 | char c; 59 | double d; 60 | }; 61 | 62 | int main() { 63 | my_struct s{100, 'H', 3.141593}; 64 | std::cout << "my_struct has " << pfr::tuple_size::value 65 | << " fields: " << pfr::io(s) << "\n"; 66 | } 67 | 68 | ``` 69 | 70 | Outputs: 71 | ``` 72 | my_struct has 3 fields: {100, H, 3.14159} 73 | ``` 74 | 75 | ### Motivating Example #2 76 | 77 | ```c++ 78 | #include 79 | #include "pfr.hpp" 80 | 81 | struct my_struct { // no ostream operator defined! 82 | std::string s; 83 | int i; 84 | }; 85 | 86 | int main() { 87 | my_struct s{{"Das ist fantastisch!"}, 100}; 88 | std::cout << "my_struct has " << pfr::tuple_size::value 89 | << " fields: " << pfr::io(s) << "\n"; 90 | } 91 | 92 | ``` 93 | 94 | Outputs: 95 | ``` 96 | my_struct has 2 fields: {"Das ist fantastisch!", 100} 97 | ``` 98 | 99 | ### Motivating Example #3 100 | 101 | ```c++ 102 | #include 103 | #include 104 | 105 | #include 106 | #include 107 | #include 108 | 109 | #include "pfr/io.hpp" 110 | 111 | namespace x3 = boost::spirit::x3; 112 | 113 | struct ast_employee { // No BOOST_FUSION_ADAPT_STRUCT defined 114 | int age; 115 | std::string forename; 116 | std::string surname; 117 | double salary; 118 | }; 119 | 120 | auto const quoted_string = x3::lexeme['"' >> +(x3::ascii::char_ - '"') >> '"']; 121 | 122 | x3::rule const employee = "employee"; 123 | auto const employee_def = 124 | x3::lit("employee") 125 | >> '{' 126 | >> x3::int_ >> ',' 127 | >> quoted_string >> ',' 128 | >> quoted_string >> ',' 129 | >> x3::double_ 130 | >> '}' 131 | ; 132 | BOOST_SPIRIT_DEFINE(employee); 133 | 134 | int main() { 135 | std::string str = R"(employee{34, "Chip", "Douglas", 2500.00})"; 136 | ast_employee emp; 137 | x3::phrase_parse(str.begin(), 138 | str.end(), 139 | employee, 140 | x3::ascii::space, 141 | emp); 142 | std::cout << pfr::io(emp) << std::endl; 143 | } 144 | 145 | ``` 146 | Outputs: 147 | ``` 148 | (34 Chip Douglas 2500) 149 | ``` 150 | 151 | 152 | ### Requirements and Limitations 153 | 154 | [See docs](https://www.boost.org/doc/libs/develop/doc/html/boost_pfr.html). 155 | 156 | ### License 157 | 158 | Distributed under the [Boost Software License, Version 1.0](https://boost.org/LICENSE_1_0.txt). 159 | -------------------------------------------------------------------------------- /build.jam: -------------------------------------------------------------------------------- 1 | # Copyright René Ferdinand Rivera Morell 2023-2024 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | require-b2 5.2 ; 7 | 8 | project /pfr 9 | : common-requirements 10 | include 11 | ; 12 | 13 | explicit 14 | [ alias boost_pfr : : : : $(boost_dependencies) ] 15 | [ alias all : boost_pfr test ] 16 | ; 17 | 18 | call-if : boost-library pfr 19 | ; 20 | 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/get.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2024 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/motivating_example0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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 | -------------------------------------------------------------------------------- /example/quick_examples.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2024 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 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | // boost-no-inspect 16 | void test_examples() { 17 | 18 | #if PFR_USE_CPP17 19 | { 20 | //[pfr_quick_examples_ops 21 | // Assert equality. 22 | // Note that the equality operator for structure is not defined. 23 | 24 | struct test { 25 | std::string f1; 26 | std::string_view f2; 27 | }; 28 | 29 | assert( 30 | pfr::eq(test{"aaa", "zomg"}, test{"aaa", "zomg"}) 31 | ); 32 | //] 33 | } 34 | #endif 35 | 36 | { 37 | //[pfr_quick_examples_for_each 38 | // Increment each field of the variable on 1 and 39 | // output the content of the variable. 40 | 41 | struct test { 42 | int f1; 43 | long f2; 44 | }; 45 | 46 | test var{42, 43}; 47 | 48 | pfr::for_each_field(var, [](auto& field) { 49 | field += 1; 50 | }); 51 | 52 | // Outputs: {43, 44} 53 | std::cout << pfr::io(var); 54 | //] 55 | } 56 | 57 | { 58 | //[pfr_quick_examples_for_each_idx 59 | // Iterate over fields of a variable and output index and 60 | // type of a variable. 61 | 62 | struct tag0{}; 63 | struct tag1{}; 64 | struct sample { 65 | tag0 a; 66 | tag1 b; 67 | }; 68 | 69 | // Outputs: 70 | // 0: tag0 71 | // 1: tag1 72 | pfr::for_each_field(sample{}, [](const auto& field, std::size_t idx) { 73 | std::cout << '\n' << idx << ": " 74 | << boost::typeindex::type_id_runtime(field); 75 | }); 76 | //] 77 | } 78 | 79 | 80 | // Disabling for MSVC as it gives a hard error on using local types: 81 | // 82 | // error C7631: 83 | // 'pfr::detail::do_not_use_PFR_with_local_types': 84 | // variable with internal linkage declared but not defined 85 | #if PFR_CORE_NAME_ENABLED && PFR_USE_CPP17 && !defined(_MSC_VER) 86 | { 87 | //[pfr_quick_examples_for_each_with_name 88 | // Print the name and value 89 | // of each element of the structure 90 | 91 | struct test { 92 | int n; 93 | std::string str; 94 | }; 95 | 96 | test var{42, "Hello, World!"}; 97 | 98 | // Outputs: 99 | // n: 42 100 | // str: Hello, World! 101 | pfr::for_each_field_with_name(var, 102 | [](std::string_view name, const auto& value) { 103 | std::cout << name << ": " << value << std::endl; 104 | }); 105 | //] 106 | } 107 | #endif 108 | 109 | { 110 | //[pfr_quick_examples_tuple_size 111 | // Getting fields count of some structure 112 | 113 | struct some { int a,b,c,d,e; }; 114 | 115 | std::cout << "Fields count in structure: " 116 | << pfr::tuple_size::value // Outputs: 5 117 | << '\n'; 118 | //] 119 | } 120 | 121 | { 122 | //[pfr_quick_examples_get 123 | // Get field by index/type and assign new value to that field 124 | 125 | struct sample { 126 | char c; 127 | float f; 128 | }; 129 | 130 | sample var{}; 131 | pfr::get<1>(var) = 42.01f; 132 | pfr::get(var) = 'A'; 133 | 134 | std::cout << var.c << var.f; // Outputs: A 42.01 135 | //] 136 | } 137 | 138 | // Disabling for MSVC as it gives a hard error on using local types: 139 | // 140 | // error C7631: 141 | // 'pfr::detail::do_not_use_PFR_with_local_types': 142 | // variable with internal linkage declared but not defined 143 | #if PFR_CORE_NAME_ENABLED && PFR_USE_CPP17 && !defined(_MSC_VER) 144 | { 145 | //[pfr_quick_examples_get_name 146 | // Get name of field by index 147 | 148 | struct sample { 149 | int f_int; 150 | long f_long; 151 | }; 152 | 153 | std::cout << pfr::get_name<0, sample>() 154 | << pfr::get_name<1, sample>(); // Outputs: f_int f_long 155 | //] 156 | } 157 | #endif 158 | 159 | #if PFR_USE_CPP17 || PFR_USE_LOOPHOLE 160 | { 161 | //[pfr_quick_examples_structure_to_tuple 162 | // Getting a std::tuple of values from structures fields 163 | 164 | struct foo { int a, b; }; 165 | struct other { 166 | char c; 167 | foo nested; 168 | }; 169 | 170 | other var{'A', {3, 4}}; 171 | std::tuple t = pfr::structure_to_tuple(var); 172 | assert(std::get<0>(t) == 'A'); 173 | assert( 174 | pfr::eq(std::get<1>(t), foo{3, 4}) 175 | ); 176 | //] 177 | } 178 | #endif 179 | 180 | #if PFR_USE_CPP17 || PFR_USE_LOOPHOLE 181 | { 182 | //[pfr_quick_examples_structure_tie 183 | // Getting a std::tuple of references to structure fields 184 | 185 | struct foo { int a, b; }; 186 | struct other { 187 | char c; 188 | foo f; 189 | }; 190 | 191 | other var{'A', {14, 15}}; 192 | std::tuple t = pfr::structure_tie(var); 193 | std::get<1>(t) = foo{1, 2}; 194 | 195 | std::cout << pfr::io(var.f); // Outputs: {1, 2} 196 | //] 197 | } 198 | #endif 199 | 200 | } // void test_examples() 201 | 202 | //[pfr_quick_examples_functions_for 203 | // Define all the comparison and IO operators for my_structure type along 204 | // with hash_value function. 205 | 206 | #include 207 | 208 | namespace my_namespace { 209 | struct my_structure { 210 | int a,b,c,d,e,f,g; 211 | // ... 212 | }; 213 | PFR_FUNCTIONS_FOR(my_structure) 214 | } 215 | //] 216 | 217 | //[pfr_quick_examples_eq_fields 218 | // Define only the equality and inequality operators for my_eq_ne_structure. 219 | 220 | #include 221 | 222 | namespace my_namespace { 223 | struct my_eq_ne_structure { 224 | float a,b,c,d,e,f,g; 225 | // ... 226 | }; 227 | 228 | inline bool operator==(const my_eq_ne_structure& x, const my_eq_ne_structure& y) { 229 | return pfr::eq_fields(x, y); 230 | } 231 | 232 | inline bool operator!=(const my_eq_ne_structure& x, const my_eq_ne_structure& y) { 233 | return pfr::ne_fields(x, y); 234 | } 235 | } 236 | //] 237 | 238 | int main() { 239 | test_examples(); 240 | } 241 | -------------------------------------------------------------------------------- /example/sample_printing.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2024 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 | -------------------------------------------------------------------------------- /include/pfr.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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/config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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_CONFIG_HPP 8 | #define PFR_CONFIG_HPP 9 | #pragma once 10 | 11 | #if __cplusplus >= 201402L || (defined(_MSC_VER) && defined(_MSVC_LANG) && _MSC_VER > 1900) 12 | #include // to get non standard platform macro definitions (__GLIBCXX__ for example) 13 | #endif 14 | 15 | /// \file pfr/config.hpp 16 | /// Contains all the macros that describe Boost.PFR configuration, like PFR_ENABLED 17 | /// 18 | /// \note This header file doesn't require C++14 Standard and supports all C++ compilers, even pre C++14 compilers (C++11, C++03...). 19 | 20 | // Reminder: 21 | // * MSVC++ 14.2 _MSC_VER == 1927 <- Loophole is known to work (Visual Studio ????) 22 | // * MSVC++ 14.1 _MSC_VER == 1916 <- Loophole is known to NOT work (Visual Studio 2017) 23 | // * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) 24 | // * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) 25 | 26 | #ifdef PFR_NOT_SUPPORTED 27 | # error Please, do not set PFR_NOT_SUPPORTED value manually, use '-DPFR_ENABLED=0' instead of it 28 | #endif 29 | 30 | #if defined(_MSC_VER) 31 | # if !defined(_MSVC_LANG) || _MSC_VER <= 1900 32 | # define PFR_NOT_SUPPORTED 1 33 | # endif 34 | #elif __cplusplus < 201402L 35 | # define PFR_NOT_SUPPORTED 1 36 | #endif 37 | 38 | #ifndef PFR_USE_LOOPHOLE 39 | # if defined(_MSC_VER) 40 | # if _MSC_VER >= 1927 41 | # define PFR_USE_LOOPHOLE 1 42 | # else 43 | # define PFR_USE_LOOPHOLE 0 44 | # endif 45 | # elif defined(__clang_major__) && __clang_major__ >= 8 46 | # define PFR_USE_LOOPHOLE 0 47 | # else 48 | # define PFR_USE_LOOPHOLE 1 49 | # endif 50 | #endif 51 | 52 | #ifndef PFR_USE_CPP17 53 | # ifdef __cpp_structured_bindings 54 | # define PFR_USE_CPP17 1 55 | # elif defined(_MSVC_LANG) 56 | # if _MSVC_LANG >= 201703L 57 | # define PFR_USE_CPP17 1 58 | # else 59 | # define PFR_USE_CPP17 0 60 | # endif 61 | # else 62 | # define PFR_USE_CPP17 0 63 | # endif 64 | #endif 65 | 66 | #if (!PFR_USE_CPP17 && !PFR_USE_LOOPHOLE) 67 | # if (defined(_MSC_VER) && _MSC_VER < 1916) ///< in Visual Studio 2017 v15.9 PFR library with classic engine normally works 68 | # define PFR_NOT_SUPPORTED 1 69 | # endif 70 | #endif 71 | 72 | #ifndef PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 73 | // Assume that libstdc++ since GCC-7.3 does not have linear instantiation depth in std::make_integral_sequence 74 | # if defined( __GLIBCXX__) && __GLIBCXX__ >= 20180101 75 | # define PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1 76 | # elif defined(_MSC_VER) 77 | # define PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 1 78 | //# elif other known working lib 79 | # else 80 | # define PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE 0 81 | # endif 82 | #endif 83 | 84 | #ifndef PFR_HAS_GUARANTEED_COPY_ELISION 85 | # if defined(__cpp_guaranteed_copy_elision) && (!defined(_MSC_VER) || _MSC_VER > 1928) 86 | # define PFR_HAS_GUARANTEED_COPY_ELISION 1 87 | # else 88 | # define PFR_HAS_GUARANTEED_COPY_ELISION 0 89 | # endif 90 | #endif 91 | 92 | #ifndef PFR_ENABLE_IMPLICIT_REFLECTION 93 | # if defined(__cpp_lib_is_aggregate) 94 | # define PFR_ENABLE_IMPLICIT_REFLECTION 1 95 | # else 96 | // There is no way to detect potential ability to be reflectable without std::is_aggregare 97 | # define PFR_ENABLE_IMPLICIT_REFLECTION 0 98 | # endif 99 | #endif 100 | 101 | #ifndef PFR_CORE_NAME_ENABLED 102 | # if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L)) 103 | # if (defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911) \ 104 | || (defined(__clang_major__) && __clang_major__ >= 12) 105 | # define PFR_CORE_NAME_ENABLED 1 106 | # else 107 | # define PFR_CORE_NAME_ENABLED 0 108 | # endif 109 | # else 110 | # define PFR_CORE_NAME_ENABLED 0 111 | # endif 112 | #endif 113 | 114 | 115 | #ifndef PFR_CORE_NAME_PARSING 116 | # if defined(_MSC_VER) && !defined(__clang__) 117 | # define PFR_CORE_NAME_PARSING (sizeof("auto __cdecl pfr::detail::name_of_field_impl<") - 1, sizeof(">(void) noexcept") - 1, backward("->")) 118 | # elif defined(__clang__) 119 | # define PFR_CORE_NAME_PARSING (sizeof("auto pfr::detail::name_of_field_impl() [MsvcWorkaround = ") - 1, sizeof("}]") - 1, backward(".")) 120 | # elif defined(__GNUC__) 121 | # define PFR_CORE_NAME_PARSING (sizeof("consteval auto pfr::detail::name_of_field_impl() [with MsvcWorkaround = ") - 1, sizeof(")]") - 1, backward("::")) 122 | # else 123 | // Default parser for other platforms... Just skip nothing! 124 | # define PFR_CORE_NAME_PARSING (0, 0, "") 125 | # endif 126 | #endif 127 | 128 | #if defined(__has_cpp_attribute) 129 | # if __has_cpp_attribute(maybe_unused) 130 | # define PFR_MAYBE_UNUSED [[maybe_unused]] 131 | # endif 132 | #endif 133 | 134 | #ifndef PFR_MAYBE_UNUSED 135 | # define PFR_MAYBE_UNUSED 136 | #endif 137 | 138 | #ifndef PFR_ENABLED 139 | # ifdef PFR_NOT_SUPPORTED 140 | # define PFR_ENABLED 0 141 | # else 142 | # define PFR_ENABLED 1 143 | # endif 144 | #endif 145 | 146 | #undef PFR_NOT_SUPPORTED 147 | 148 | #ifndef PFR_BEGIN_MODULE_EXPORT 149 | # define PFR_BEGIN_MODULE_EXPORT 150 | #endif 151 | 152 | #ifndef PFR_END_MODULE_EXPORT 153 | # define PFR_END_MODULE_EXPORT 154 | #endif 155 | 156 | #endif // PFR_CONFIG_HPP 157 | -------------------------------------------------------------------------------- /include/pfr/core.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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_CORE_HPP 7 | #define PFR_CORE_HPP 8 | #pragma once 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include // metaprogramming stuff 22 | 23 | #include 24 | 25 | /// \file pfr/core.hpp 26 | /// Contains all the basic tuple-like interfaces \forcedlink{get}, \forcedlink{tuple_size}, \forcedlink{tuple_element_t}, and others. 27 | /// 28 | /// \b Synopsis: 29 | 30 | namespace pfr { 31 | 32 | PFR_BEGIN_MODULE_EXPORT 33 | 34 | /// \brief Returns reference or const reference to a field with index `I` in \aggregate `val`. 35 | /// Overload taking the type `U` returns reference or const reference to a field 36 | /// with provided type `U` in \aggregate `val` if there's only one field of such type in `val`. 37 | /// 38 | /// \b Example: 39 | /// \code 40 | /// struct my_struct { int i, short s; }; 41 | /// my_struct s {10, 11}; 42 | /// 43 | /// assert(pfr::get<0>(s) == 10); 44 | /// pfr::get<1>(s) = 0; 45 | /// 46 | /// assert(pfr::get(s) == 10); 47 | /// pfr::get(s) = 11; 48 | /// \endcode 49 | template 50 | constexpr decltype(auto) get(const T& val) noexcept { 51 | return detail::sequence_tuple::get( detail::tie_as_tuple(val) ); 52 | } 53 | 54 | /// \overload get 55 | template 56 | constexpr decltype(auto) get(T& val 57 | #if !PFR_USE_CPP17 58 | , std::enable_if_t::value>* = nullptr 59 | #endif 60 | ) noexcept { 61 | return detail::sequence_tuple::get( detail::tie_as_tuple(val) ); 62 | } 63 | 64 | #if !PFR_USE_CPP17 65 | /// \overload get 66 | template 67 | constexpr auto get(T&, std::enable_if_t::value>* = nullptr) noexcept { 68 | static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling pfr::get on non const non assignable type is allowed only in C++17"); 69 | return 0; 70 | } 71 | #endif 72 | 73 | 74 | /// \overload get 75 | template 76 | constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference::value>* = nullptr) noexcept { 77 | return std::move(detail::sequence_tuple::get( detail::tie_as_tuple(val) )); 78 | } 79 | 80 | 81 | /// \overload get 82 | template 83 | constexpr const U& get(const T& val) noexcept { 84 | return detail::sequence_tuple::get_by_type_impl( detail::tie_as_tuple(val) ); 85 | } 86 | 87 | 88 | /// \overload get 89 | template 90 | constexpr U& get(T& val 91 | #if !PFR_USE_CPP17 92 | , std::enable_if_t::value>* = nullptr 93 | #endif 94 | ) noexcept { 95 | return detail::sequence_tuple::get_by_type_impl( detail::tie_as_tuple(val) ); 96 | } 97 | 98 | #if !PFR_USE_CPP17 99 | /// \overload get 100 | template 101 | constexpr U& get(T&, std::enable_if_t::value>* = nullptr) noexcept { 102 | static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling pfr::get on non const non assignable type is allowed only in C++17"); 103 | return 0; 104 | } 105 | #endif 106 | 107 | 108 | /// \overload get 109 | template 110 | constexpr U&& get(T&& val, std::enable_if_t< std::is_rvalue_reference::value>* = nullptr) noexcept { 111 | return std::move(detail::sequence_tuple::get_by_type_impl( detail::tie_as_tuple(val) )); 112 | } 113 | 114 | 115 | /// \brief `tuple_element` has a member typedef `type` that returns the type of a field with index I in \aggregate T. 116 | /// 117 | /// \b Example: 118 | /// \code 119 | /// std::vector< pfr::tuple_element<0, my_structure>::type > v; 120 | /// \endcode 121 | template 122 | using tuple_element = detail::sequence_tuple::tuple_element()) ) >; 123 | 124 | 125 | /// \brief Type of a field with index `I` in \aggregate `T`. 126 | /// 127 | /// \b Example: 128 | /// \code 129 | /// std::vector< pfr::tuple_element_t<0, my_structure> > v; 130 | /// \endcode 131 | template 132 | using tuple_element_t = typename tuple_element::type; 133 | 134 | 135 | /// \brief Creates a `std::tuple` from fields of an \aggregate `val`. 136 | /// 137 | /// \b Example: 138 | /// \code 139 | /// struct my_struct { int i, short s; }; 140 | /// my_struct s {10, 11}; 141 | /// std::tuple t = pfr::structure_to_tuple(s); 142 | /// assert(get<0>(t) == 10); 143 | /// \endcode 144 | template 145 | constexpr auto structure_to_tuple(const T& val) { 146 | return detail::make_stdtuple_from_tietuple( 147 | detail::tie_as_tuple(val), 148 | detail::make_index_sequence< tuple_size_v >() 149 | ); 150 | } 151 | 152 | 153 | /// \brief std::tie` like function that ties fields of a structure. 154 | /// 155 | /// \returns a `std::tuple` with lvalue and const lvalue references to fields of an \aggregate `val`. 156 | /// 157 | /// \b Example: 158 | /// \code 159 | /// void foo(const int&, const short&); 160 | /// struct my_struct { int i, short s; }; 161 | /// 162 | /// const my_struct const_s{1, 2}; 163 | /// std::apply(foo, pfr::structure_tie(const_s)); 164 | /// 165 | /// my_struct s; 166 | /// pfr::structure_tie(s) = std::tuple{10, 11}; 167 | /// assert(s.s == 11); 168 | /// \endcode 169 | template 170 | constexpr auto structure_tie(const T& val) noexcept { 171 | return detail::make_conststdtiedtuple_from_tietuple( 172 | detail::tie_as_tuple(const_cast(val)), 173 | detail::make_index_sequence< tuple_size_v >() 174 | ); 175 | } 176 | 177 | 178 | /// \overload structure_tie 179 | template 180 | constexpr auto structure_tie(T& val 181 | #if !PFR_USE_CPP17 182 | , std::enable_if_t::value>* = nullptr 183 | #endif 184 | ) noexcept { 185 | return detail::make_stdtiedtuple_from_tietuple( 186 | detail::tie_as_tuple(val), 187 | detail::make_index_sequence< tuple_size_v >() 188 | ); 189 | } 190 | 191 | #if !PFR_USE_CPP17 192 | /// \overload structure_tie 193 | template 194 | constexpr auto structure_tie(T&, std::enable_if_t::value>* = nullptr) noexcept { 195 | static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling pfr::structure_tie on non const non assignable type is allowed only in C++17"); 196 | return 0; 197 | } 198 | #endif 199 | 200 | 201 | /// \overload structure_tie 202 | template 203 | constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference::value>* = nullptr) noexcept { 204 | static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling pfr::structure_tie on rvalue references is forbidden"); 205 | return 0; 206 | } 207 | 208 | /// Calls `func` for each field of a `value`. 209 | /// 210 | /// \param func must have one of the following signatures: 211 | /// * any_return_type func(U&& field) // field of value is perfect forwarded to function 212 | /// * any_return_type func(U&& field, std::size_t i) 213 | /// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant` 214 | /// 215 | /// \param value To each field of this variable will be the `func` applied. 216 | /// 217 | /// \b Example: 218 | /// \code 219 | /// struct my_struct { int i, short s; }; 220 | /// int sum = 0; 221 | /// pfr::for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; }); 222 | /// assert(sum == 42); 223 | /// \endcode 224 | template 225 | constexpr void for_each_field(T&& value, F&& func) { 226 | return ::pfr::detail::for_each_field(std::forward(value), std::forward(func)); 227 | } 228 | 229 | /// \brief std::tie-like function that allows assigning to tied values from aggregates. 230 | /// 231 | /// \returns an object with lvalue references to `args...`; on assignment of an \aggregate value to that 232 | /// object each field of an aggregate is assigned to the corresponding `args...` reference. 233 | /// 234 | /// \b Example: 235 | /// \code 236 | /// auto f() { 237 | /// struct { struct { int x, y } p; short s; } res { { 4, 5 }, 6 }; 238 | /// return res; 239 | /// } 240 | /// auto [p, s] = f(); 241 | /// pfr::tie_from_structure(p, s) = f(); 242 | /// \endcode 243 | template 244 | constexpr detail::tie_from_structure_tuple tie_from_structure(Elements&... args) noexcept { 245 | return detail::tie_from_structure_tuple(args...); 246 | } 247 | 248 | PFR_END_MODULE_EXPORT 249 | 250 | } // namespace pfr 251 | 252 | #endif // PFR_CORE_HPP 253 | -------------------------------------------------------------------------------- /include/pfr/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_CORE_NAME_HPP 12 | #define PFR_CORE_NAME_HPP 13 | #pragma once 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include // for std::size_t 24 | 25 | #include 26 | 27 | /// \file pfr/core_name.hpp 28 | /// Contains functions \forcedlink{get_name} and \forcedlink{names_as_array} to know which names each field of any \aggregate has. 29 | /// 30 | /// \fnrefl for details. 31 | /// 32 | /// \b Synopsis: 33 | 34 | namespace pfr { 35 | 36 | PFR_BEGIN_MODULE_EXPORT 37 | 38 | /// \brief Returns name of a field with index `I` in \aggregate `T`. 39 | /// 40 | /// \b Example: 41 | /// \code 42 | /// struct my_struct { int i, short s; }; 43 | /// 44 | /// assert(pfr::get_name<0, my_struct>() == "i"); 45 | /// assert(pfr::get_name<1, my_struct>() == "s"); 46 | /// \endcode 47 | template 48 | constexpr 49 | #ifdef PFR_DOXYGEN_INVOKED 50 | std::string_view 51 | #else 52 | auto 53 | #endif 54 | get_name() noexcept { 55 | return detail::get_name(); 56 | } 57 | 58 | // FIXME: implement this 59 | // template 60 | // constexpr auto get_name() noexcept { 61 | // return detail::sequence_tuple::get_by_type_impl( detail::tie_as_names_tuple() ); 62 | // } 63 | 64 | /// \brief Creates a `std::array` from names of fields of an \aggregate `T`. 65 | /// 66 | /// \b Example: 67 | /// \code 68 | /// struct my_struct { int i, short s; }; 69 | /// std::array a = pfr::names_as_array(); 70 | /// assert(a[0] == "i"); 71 | /// \endcode 72 | template 73 | constexpr 74 | #ifdef PFR_DOXYGEN_INVOKED 75 | std::array> 76 | #else 77 | auto 78 | #endif 79 | names_as_array() noexcept { 80 | return detail::make_stdarray_from_tietuple( 81 | detail::tie_as_names_tuple(), 82 | detail::make_index_sequence< tuple_size_v >(), 83 | 1L 84 | ); 85 | } 86 | 87 | 88 | /// Calls `func` for each field with its name of a `value` 89 | /// 90 | /// \param func must have one of the following signatures: 91 | /// * any_return_type func(std::string_view name, U&& field) // field of value is perfect forwarded to function 92 | /// * any_return_type func(std::string_view name, U&& field, std::size_t i) 93 | /// * any_return_type func(std::string_view name, U&& value, I i) // Here I is an `std::integral_constant` 94 | /// 95 | /// \param value To each field of this variable will be the `func` applied. 96 | /// 97 | /// \b Example: 98 | /// \code 99 | /// struct Toto { int a; char c; }; 100 | /// Toto t {5, 'c'}; 101 | /// auto print = [](std::string_view name, const auto& value){ std::cout << "Name: " << name << " Value: " << value << std::endl; }; 102 | /// for_each_field_with_name(t, print); 103 | /// \endcode 104 | template 105 | constexpr void for_each_field_with_name(T&& value, F&& func) { 106 | return pfr::detail::for_each_field_with_name(std::forward(value), std::forward(func)); 107 | } 108 | 109 | PFR_END_MODULE_EXPORT 110 | 111 | } // namespace pfr 112 | 113 | #endif // PFR_CORE_NAME_HPP 114 | -------------------------------------------------------------------------------- /include/pfr/detail/config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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 | -------------------------------------------------------------------------------- /include/pfr/detail/core.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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 | -------------------------------------------------------------------------------- /include/pfr/detail/core14_loophole.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017-2018 Alexandr Poltavsky, Antony Polukhin. 2 | // Copyright (c) 2019-2024 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 | // The Great Type Loophole (C++14) 9 | // Initial implementation by Alexandr Poltavsky, http://alexpolt.github.io 10 | // 11 | // Description: 12 | // The Great Type Loophole is a technique that allows to exchange type information with template 13 | // instantiations. Basically you can assign and read type information during compile time. 14 | // Here it is used to detect data members of a data type. I described it for the first time in 15 | // this blog post http://alexpolt.github.io/type-loophole.html . 16 | // 17 | // This technique exploits the http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 18 | // CWG 2118. Stateful metaprogramming via friend injection 19 | // Note: CWG agreed that such techniques should be ill-formed, although the mechanism for prohibiting them is as yet undetermined. 20 | 21 | #ifndef PFR_DETAIL_CORE14_LOOPHOLE_HPP 22 | #define PFR_DETAIL_CORE14_LOOPHOLE_HPP 23 | #pragma once 24 | 25 | #include 26 | 27 | #ifdef PFR_HAS_STD_MODULE 28 | import std; 29 | #else 30 | #include 31 | #include 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | 43 | #ifdef __clang__ 44 | # pragma clang diagnostic push 45 | # pragma clang diagnostic ignored "-Wmissing-braces" 46 | # pragma clang diagnostic ignored "-Wundefined-inline" 47 | # pragma clang diagnostic ignored "-Wundefined-internal" 48 | # pragma clang diagnostic ignored "-Wmissing-field-initializers" 49 | #elif defined(__GNUC__) 50 | # pragma GCC diagnostic push 51 | # pragma GCC diagnostic ignored "-Wnon-template-friend" 52 | #endif 53 | 54 | 55 | namespace pfr { namespace detail { 56 | 57 | // tag generates friend declarations and helps with overload resolution. 58 | // There are two types: one with the auto return type, which is the way we read types later. 59 | // The second one is used in the detection of instantiations without which we'd get multiple 60 | // definitions. 61 | 62 | template 63 | struct tag { 64 | friend auto loophole(tag); 65 | }; 66 | 67 | // The definitions of friend functions. 68 | template 69 | struct fn_def_lref { 70 | friend auto loophole(tag) { 71 | // Standard Library containers do not SFINAE on invalid copy constructor. Because of that std::vector> reports that it is copyable, 72 | // which leads to an instantiation error at this place. 73 | // 74 | // To workaround the issue, we check that the type U is movable, and move it in that case. 75 | using no_extents_t = std::remove_all_extents_t; 76 | return static_cast< std::conditional_t::value, no_extents_t&&, no_extents_t&> >( 77 | pfr::detail::unsafe_declval() 78 | ); 79 | } 80 | }; 81 | template 82 | struct fn_def_rref { 83 | friend auto loophole(tag) { return std::move(pfr::detail::unsafe_declval< std::remove_all_extents_t& >()); } 84 | }; 85 | 86 | 87 | // Those specializations are to avoid multiple definition errors. 88 | template 89 | struct fn_def_lref {}; 90 | 91 | template 92 | struct fn_def_rref {}; 93 | 94 | 95 | // This has a templated conversion operator which in turn triggers instantiations. 96 | // Important point, using sizeof seems to be more reliable. Also default template 97 | // arguments are "cached" (I think). To fix that I provide a U template parameter to 98 | // the ins functions which do the detection using constexpr friend functions and SFINAE. 99 | template 100 | struct loophole_ubiq_lref { 101 | template static std::size_t ins(...); 102 | template{})) > static char ins(int); 103 | 104 | template(0)) == sizeof(char)>)> 105 | constexpr operator U&() const&& noexcept; // `const&&` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior. 106 | }; 107 | 108 | template 109 | struct loophole_ubiq_rref { 110 | template static std::size_t ins(...); 111 | template{})) > static char ins(int); 112 | 113 | template(0)) == sizeof(char)>)> 114 | constexpr operator U&&() const&& noexcept; // `const&&` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior. 115 | }; 116 | 117 | 118 | // This is a helper to turn a data structure into a tuple. 119 | template 120 | struct loophole_type_list_lref; 121 | 122 | template 123 | struct loophole_type_list_lref< T, std::index_sequence > 124 | // Instantiating loopholes: 125 | : sequence_tuple::tuple< decltype(T{ loophole_ubiq_lref{}... }, 0) > 126 | { 127 | using type = sequence_tuple::tuple< decltype(loophole(tag{}))... >; 128 | }; 129 | 130 | 131 | template 132 | struct loophole_type_list_rref; 133 | 134 | template 135 | struct loophole_type_list_rref< T, std::index_sequence > 136 | // Instantiating loopholes: 137 | : sequence_tuple::tuple< decltype(T{ loophole_ubiq_rref{}... }, 0) > 138 | { 139 | using type = sequence_tuple::tuple< decltype(loophole(tag{}))... >; 140 | }; 141 | 142 | 143 | // Lazily returns loophole_type_list_{lr}ref. 144 | template 145 | struct loophole_type_list_selector { 146 | using type = loophole_type_list_lref; 147 | }; 148 | 149 | template 150 | struct loophole_type_list_selector { 151 | using type = loophole_type_list_rref; 152 | }; 153 | 154 | template 155 | auto tie_as_tuple_loophole_impl(T& lvalue) noexcept { 156 | using type = std::remove_cv_t>; 157 | using indexes = detail::make_index_sequence()>; 158 | using loophole_type_list = typename detail::loophole_type_list_selector< 159 | std::is_copy_constructible>::value, type, indexes 160 | >::type; 161 | using tuple_type = typename loophole_type_list::type; 162 | 163 | return pfr::detail::make_flat_tuple_of_references( 164 | lvalue, 165 | offset_based_getter{}, 166 | size_t_<0>{}, 167 | size_t_{} 168 | ); 169 | } 170 | 171 | template 172 | auto tie_as_tuple(T& val) noexcept { 173 | static_assert( 174 | !std::is_union::value, 175 | "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." 176 | ); 177 | return pfr::detail::tie_as_tuple_loophole_impl( 178 | val 179 | ); 180 | } 181 | 182 | template 183 | void for_each_field_dispatcher(T& t, F&& f, std::index_sequence) { 184 | static_assert( 185 | !std::is_union::value, 186 | "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." 187 | ); 188 | std::forward(f)( 189 | pfr::detail::tie_as_tuple_loophole_impl(t) 190 | ); 191 | } 192 | 193 | }} // namespace pfr::detail 194 | 195 | 196 | #ifdef __clang__ 197 | # pragma clang diagnostic pop 198 | #elif defined(__GNUC__) 199 | # pragma GCC diagnostic pop 200 | #endif 201 | 202 | 203 | #endif // PFR_DETAIL_CORE14_LOOPHOLE_HPP 204 | 205 | -------------------------------------------------------------------------------- /include/pfr/detail/core17.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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/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 | -------------------------------------------------------------------------------- /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/core_name20_static.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_NAME20_STATIC_HPP 12 | #define PFR_DETAIL_CORE_NAME20_STATIC_HPP 13 | #pragma once 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef PFR_HAS_STD_MODULE 26 | import std; 27 | #else 28 | #include 29 | #include 30 | #include 31 | #include // for std::addressof 32 | #endif 33 | 34 | namespace pfr { namespace detail { 35 | 36 | struct core_name_skip { 37 | std::size_t size_at_begin; 38 | std::size_t size_at_end; 39 | bool is_backward; 40 | std::string_view until_runtime; 41 | 42 | consteval std::string_view apply(std::string_view sv) const noexcept { 43 | // We use std::min here to make the compiler diagnostic shorter and 44 | // cleaner in case of misconfigured PFR_CORE_NAME_PARSING 45 | sv.remove_prefix((std::min)(size_at_begin, sv.size())); 46 | sv.remove_suffix((std::min)(size_at_end, sv.size())); 47 | if (until_runtime.empty()) { 48 | return sv; 49 | } 50 | 51 | const auto found = is_backward ? sv.rfind(until_runtime) 52 | : sv.find(until_runtime); 53 | 54 | const auto cut_until = found + until_runtime.size(); 55 | const auto safe_cut_until = (std::min)(cut_until, sv.size()); 56 | return sv.substr(safe_cut_until); 57 | } 58 | }; 59 | 60 | struct backward { 61 | explicit consteval backward(std::string_view value) noexcept 62 | : value(value) 63 | {} 64 | 65 | std::string_view value; 66 | }; 67 | 68 | consteval core_name_skip make_core_name_skip(std::size_t size_at_begin, 69 | std::size_t size_at_end, 70 | std::string_view until_runtime) noexcept 71 | { 72 | return core_name_skip{size_at_begin, size_at_end, false, until_runtime}; 73 | } 74 | 75 | consteval core_name_skip make_core_name_skip(std::size_t size_at_begin, 76 | std::size_t size_at_end, 77 | backward until_runtime) noexcept 78 | { 79 | return core_name_skip{size_at_begin, size_at_end, true, until_runtime.value}; 80 | } 81 | 82 | // it might be compilation failed without this workaround sometimes 83 | // See https://github.com/llvm/llvm-project/issues/41751 for details 84 | template 85 | consteval std::string_view clang_workaround(std::string_view value) noexcept 86 | { 87 | return value; 88 | } 89 | 90 | template 91 | consteval auto name_of_field_impl() noexcept { 92 | // Some of the following compiler specific macro may be defined only 93 | // inside the function body: 94 | 95 | #ifndef PFR_FUNCTION_SIGNATURE 96 | # if defined(__FUNCSIG__) 97 | # define PFR_FUNCTION_SIGNATURE __FUNCSIG__ 98 | # elif defined(__PRETTY_FUNCTION__) || defined(__GNUC__) || defined(__clang__) 99 | # define PFR_FUNCTION_SIGNATURE __PRETTY_FUNCTION__ 100 | # else 101 | # define PFR_FUNCTION_SIGNATURE "" 102 | # endif 103 | #endif 104 | 105 | constexpr std::string_view sv = detail::clang_workaround(PFR_FUNCTION_SIGNATURE); 106 | static_assert(!sv.empty(), 107 | "====================> Boost.PFR: Field reflection parser configured in a wrong way. " 108 | "Please define the PFR_FUNCTION_SIGNATURE to a compiler specific macro, " 109 | "that outputs the whole function signature including non-type template parameters." 110 | ); 111 | 112 | constexpr auto skip = detail::make_core_name_skip PFR_CORE_NAME_PARSING; 113 | static_assert(skip.size_at_begin + skip.size_at_end + skip.until_runtime.size() < sv.size(), 114 | "====================> Boost.PFR: Field reflection parser configured in a wrong way. " 115 | "It attempts to skip more chars than available. " 116 | "Please define PFR_CORE_NAME_PARSING to correct values. See documentation section " 117 | "'Limitations and Configuration' for more information." 118 | ); 119 | constexpr auto fn = skip.apply(sv); 120 | static_assert( 121 | !fn.empty(), 122 | "====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. " 123 | "It skipped all the input, leaving the field name empty. " 124 | "Please define PFR_CORE_NAME_PARSING to correct values. See documentation section " 125 | "'Limitations and Configuration' for more information." 126 | ); 127 | auto res = std::array{}; 128 | 129 | auto* out = res.data(); 130 | for (auto x: fn) { 131 | *out = x; 132 | ++out; 133 | } 134 | 135 | return res; 136 | } 137 | 138 | #ifdef __clang__ 139 | #pragma clang diagnostic push 140 | #pragma clang diagnostic ignored "-Wundefined-var-template" 141 | 142 | // clang 16 and earlier don't support address of non-static member as template parameter 143 | // but fortunately it's possible to use C++20 non-type template parameters in another way 144 | // even in clang 16 and more older clangs 145 | // all we need is to wrap pointer into 'clang_wrapper_t' and then pass it into template 146 | template 147 | struct clang_wrapper_t { 148 | T v; 149 | }; 150 | template 151 | clang_wrapper_t(T) -> clang_wrapper_t; 152 | 153 | template 154 | constexpr auto make_clang_wrapper(const T& arg) noexcept { 155 | return clang_wrapper_t{arg}; 156 | } 157 | 158 | #else 159 | 160 | template 161 | constexpr const T& make_clang_wrapper(const T& arg) noexcept { 162 | // It's everything OK with address of non-static member as template parameter support on this compiler 163 | // so we don't need a wrapper here, just pass the pointer into template 164 | return arg; 165 | } 166 | 167 | #endif 168 | 169 | template 170 | consteval auto name_of_field() noexcept { 171 | // Sanity check: known field name must match the deduced one 172 | static_assert( 173 | sizeof(MsvcWorkaround) // do not trigger if `name_of_field()` is not used 174 | && std::string_view{ 175 | detail::name_of_field_impl< 176 | core_name_skip, detail::make_clang_wrapper(std::addressof( 177 | detail::fake_object().size_at_begin 178 | )) 179 | >().data() 180 | } == "size_at_begin", 181 | "====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. " 182 | "It does not return the proper field name. " 183 | "Please define PFR_CORE_NAME_PARSING to correct values. See documentation section " 184 | "'Limitations and Configuration' for more information." 185 | ); 186 | 187 | return detail::name_of_field_impl(); 188 | } 189 | 190 | // Storing part of a string literal into an array minimizes the binary size. 191 | // 192 | // Without passing 'T' into 'name_of_field' different fields from different structures might have the same name! 193 | // See https://developercommunity.visualstudio.com/t/__FUNCSIG__-outputs-wrong-value-with-C/10458554 for details 194 | template 195 | inline constexpr auto stored_name_of_field = detail::name_of_field( 197 | detail::tie_as_tuple(detail::fake_object()) 198 | ))) 199 | >(); 200 | 201 | #ifdef __clang__ 202 | #pragma clang diagnostic pop 203 | #endif 204 | 205 | template 206 | constexpr auto tie_as_names_tuple_impl(std::index_sequence) noexcept { 207 | return detail::sequence_tuple::make_sequence_tuple(std::string_view{stored_name_of_field.data()}...); 208 | } 209 | 210 | template 211 | constexpr std::string_view get_name() noexcept { 212 | static_assert( 213 | !std::is_union::value, 214 | "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." 215 | ); 216 | static_assert( 217 | !std::is_array::value, 218 | "====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members" 219 | ); 220 | static_assert( 221 | sizeof(T) && PFR_USE_CPP17, 222 | "====================> Boost.PFR: Extraction of field's names is allowed only when the PFR_USE_CPP17 macro enabled." 223 | ); 224 | 225 | return stored_name_of_field.data(); 226 | } 227 | 228 | template 229 | constexpr auto tie_as_names_tuple() noexcept { 230 | static_assert( 231 | !std::is_union::value, 232 | "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info." 233 | ); 234 | static_assert( 235 | !std::is_array::value, 236 | "====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members" 237 | ); 238 | static_assert( 239 | sizeof(T) && PFR_USE_CPP17, 240 | "====================> Boost.PFR: Extraction of field's names is allowed only when the PFR_USE_CPP17 macro enabled." 241 | ); 242 | 243 | return detail::tie_as_names_tuple_impl(detail::make_index_sequence()>{}); 244 | } 245 | 246 | template 247 | constexpr void for_each_field_with_name(T&& value, F&& func) { 248 | return pfr::detail::for_each_field( 249 | std::forward(value), 250 | [f = std::forward(func)](auto&& field, auto index) mutable { 251 | using IndexType = decltype(index); 252 | using FieldType = decltype(field); 253 | constexpr auto name = pfr::detail::get_name, IndexType::value>(); 254 | if constexpr (std::is_invocable_v) { 255 | f(name, std::forward(field), index); 256 | } else { 257 | f(name, std::forward(field)); 258 | } 259 | }); 260 | } 261 | 262 | }} // namespace pfr::detail 263 | 264 | #endif // PFR_DETAIL_CORE_NAME20_STATIC_HPP 265 | 266 | -------------------------------------------------------------------------------- /include/pfr/detail/detectors.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2024 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 | #ifdef PFR_HAS_STD_MODULE 13 | import std; 14 | #else 15 | #include 16 | #include 17 | #endif 18 | 19 | namespace pfr { namespace detail { 20 | ///////////////////// `value` is true if Detector does not compile (SFINAE) 21 | struct can_not_apply{}; 22 | 23 | template