2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-20 16:52:13 +00:00

Compare commits

..

79 Commits
1.0.4 ... help

Author SHA1 Message Date
Antony Polukhin
3daf98c9e9 change "std" status to "proposal" due to https:/wg21.link/p2141 2020-12-18 13:45:16 +03:00
Antony Polukhin
a5f84b38a6 Disable constexpr_ops test on MSVC 2020-12-17 20:28:38 +03:00
Antony Polukhin
e88e44cc14 comparison functions are now constexpr (fixes #52) 2020-12-16 18:42:40 +03:00
Antony Polukhin
f28952c544 fix attempt for #61 2020-12-16 17:38:15 +03:00
Antony Polukhin
eb37b11dfc attempt to fix test 2020-12-16 11:58:39 +03:00
Antony Polukhin
2719abe88c fix typos in SimpleAggregate (fixes #63) 2020-12-16 10:56:53 +03:00
Antony Polukhin
01af26370f Merge pull request #64 from eldiener/develop
Add "cxxstd" json field. The "cxxstd" json field is being added to ea…
2020-12-16 10:53:09 +03:00
Edward Diener
eb7a7a2d92 Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries whose minumum C++ standard compilation level is C++11 on up. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. 2020-12-16 00:42:20 -05:00
Antony Polukhin
33b5003883 fixes 2020-12-15 15:46:17 +03:00
Antony Polukhin
99f5037a00 add test on reflecting structure with std::optional<std::chrono::seconds> (refs #61) 2020-11-28 20:30:22 +03:00
Antony Polukhin
e15cb59f76 Update the docs 2020-11-02 20:07:34 +03:00
Antony Polukhin
8fd5392b3b Print config info in tests. Use std::make_index_sequence in more cases 2020-10-27 13:31:23 +03:00
Antony Polukhin
1a6ff4cf77 Less MSVC warnings, enable Loophole on _MSVC_VER>=1927 and disable Loophole tests on _MSVC_VER<=1916 2020-10-24 15:48:22 +03:00
Antony Polukhin
57cb27a5ca MSVC related workarounds 2020-10-23 21:50:10 +03:00
Antony Polukhin
812f3f62f3 MSVC experiment: gathering errors on loophole usage 2020-10-22 22:44:56 +03:00
Antony Polukhin
9c6f5fd2c0 test on unconstrained forwarding ref field reflection 2020-10-21 15:31:39 +03:00
Antony Polukhin
2568ef5fe6 fix reflection of unconstrained const rvalue constructible field 2020-10-21 15:27:14 +03:00
Antony Polukhin
ed4505ca05 Make the generate_cpp17.py script python version agnostic and add smoke test that the script works (fixes #57) 2020-10-21 14:39:51 +03:00
Antony Polukhin
8c4934c17d Merge pull request #58 from akrzemi1/better_errors
better error messages
2020-10-20 21:26:55 +03:00
Antony Polukhin
00643f5aff doc improvement ideas from Andrzej Krzemienski 2020-10-20 20:09:34 +03:00
Andrzej Krzemienski
5a1cc330b9 better error messages 2020-10-19 22:06:48 +02:00
Antony Polukhin
43c671a2ee fix warnings in tests and improve CI 2020-10-19 19:30:36 +03:00
Antony Polukhin
890d352327 attempt to fix coverage 2020-10-16 19:11:44 +03:00
Antony Polukhin
affa1ec6c0 Improve Readme 2020-10-16 19:11:30 +03:00
Antony Polukhin
cef16a47a5 fix warnings 2020-10-16 19:11:12 +03:00
Antony Polukhin
d797b30d3b CI fixes (1) 2020-10-16 11:28:08 +03:00
Antony Polukhin
1245236d16 CI fixes 2020-10-16 10:56:24 +03:00
Antony Polukhin
6168a1e000 CI fixes and a reliable detection of loophole support by compiler 2020-10-15 23:01:01 +03:00
Antony Polukhin
43014fd9f5 CI fix attempt 2020-10-15 22:43:54 +03:00
Antony Polukhin
10816795e7 Merge github.com:boostorg/pfr into develop 2020-10-15 22:08:19 +03:00
Antony Polukhin
57d8482245 CI fixes and fix some issues with docs (fixes #55) 2020-10-15 22:07:07 +03:00
Glen Fernandes
fe326ac9e4 Add index.html for boost.org/libs/pfr redirection 2020-10-15 14:54:19 -04:00
Glen Fernandes
3582a4597f Add meta/libraries.json 2020-10-15 12:29:39 -04:00
Antony Polukhin
3b369d6303 improve docs (refs #55) 2020-10-14 21:26:11 +03:00
Antony Polukhin
d2ac7325bd more polishings for the docs 2020-10-14 10:30:09 +03:00
Antony Polukhin
dfb3771e4f Use HTTPS 2020-10-13 22:47:34 +03:00
Antony Polukhin
4fe0615262 more fixes for the docs 2020-10-13 22:39:50 +03:00
Antony Polukhin
020b855686 more cleanups for the docs 2020-10-13 20:36:22 +03:00
Antony Polukhin
642937c7f4 fixes 2020-10-12 21:56:32 +03:00
Antony Polukhin
4ec21adbab more cleanups for the docs 2020-10-12 21:03:03 +03:00
Antony Polukhin
5daf55c5e2 improvements for reference section 2020-10-11 22:17:01 +03:00
Antony Polukhin
8d26298e0a polishing docs 2020-10-11 22:00:36 +03:00
Antony Polukhin
4d89b42a66 cleanup the docs 2020-10-11 21:35:19 +03:00
Antony Polukhin
f40d2f773a cleanup quck examples 2020-10-11 21:09:14 +03:00
Antony Polukhin
759b84d7cc change read|write to io* manipulators 2020-10-11 17:47:52 +03:00
Antony Polukhin
4f52ff8516 stop forcing engine on MSVC 2020-10-11 14:54:42 +03:00
Antony Polukhin
11dc14e61b start ops rewrite 2020-10-11 14:40:46 +03:00
Antony Polukhin
77110ea65f docs rewrite started 2020-10-10 23:08:06 +03:00
Antony Polukhin
2ae179cc00 bugfixes and tests 2020-10-10 16:43:10 +03:00
Antony Polukhin
5713fa0aa7 minor 2020-10-09 22:26:25 +03:00
Antony Polukhin
7fe5f9b9b4 Fix docs 2020-10-09 22:18:24 +03:00
Antony Polukhin
2331a3bc6b more polishings 2020-10-09 22:04:00 +03:00
Antony Polukhin
af4120c5fd fixes for docs and tests 2020-10-09 21:40:19 +03:00
Antony Polukhin
44c3ae3969 cleanup the docs and headers, disable classic core on MSVC tests 2020-10-09 21:26:38 +03:00
Antony Polukhin
0acdbfc7a5 clenups in tests 2020-10-09 20:44:07 +03:00
Antony Polukhin
fa119761f6 cleanups 2020-10-08 23:34:30 +03:00
Antony Polukhin
1d64f96a1e more file moves and cleanups 2020-10-08 23:07:35 +03:00
Antony Polukhin
59357a7cb5 start the flat version dropping 2020-10-08 22:56:44 +03:00
Antony Polukhin
7bff3ec9f2 documentation fixes 2020-10-06 14:09:06 +03:00
Antony Polukhin
77e714c79d add test casses from review by Richard Hodges 2020-10-06 13:34:36 +03:00
Antony Polukhin
655662b3e2 allow structure tie usages on const structures 2020-10-06 12:39:04 +03:00
Antony Polukhin
dd0d53eded more polishings for the docs 2020-10-05 20:14:26 +03:00
Antony Polukhin
c32fb3271f more fixes and clarifications for the docs 2020-10-05 19:59:02 +03:00
Antony Polukhin
1365e2779b Add an example on how to customize printing (fixes #47) 2020-10-05 19:10:13 +03:00
Antony Polukhin
ea068caf14 Rewrite the Motivation section; less "reflection" more "representation" in docs 2020-10-05 18:49:40 +03:00
Antony Polukhin
a16d99b7f1 Fix issues found by Steven Watanabe and update docs to show limitations from #36 and #35 (fixes #35) 2020-10-04 14:46:13 +03:00
Antony Polukhin
b56e45f277 Merge pull request #50 from ericLemanissier/patch-1
add license
2020-10-04 13:36:10 +03:00
ericLemanissier
19c4eead83 add license 2020-10-02 13:53:59 +02:00
Antony Polukhin
03afd0b83c Merge pull request #49 from akrzemi1/patch-1
Fix spelling in fields_count.hpp
2020-10-02 10:50:41 +03:00
Andrzej Krzemieński
aeaa6698e5 Fix spelling in fields_count.hpp 2020-09-30 08:31:33 +02:00
Antony Polukhin
5c94e55195 Disable tests on segfaulting compiler 2020-09-08 16:34:59 +03:00
Antony Polukhin
467f3c1db1 revert MSVC experiment and avoid warning in test 2020-09-04 16:10:06 +03:00
Antony Polukhin
2c23291231 experiment: enable more MSVC tests 2020-09-04 15:51:22 +03:00
Antony Polukhin
00e45d8b9c Update appveyor.yml 2020-08-28 21:47:25 +03:00
Antony Polukhin
e0b40b15bd Update Jamfile.v2 2020-08-28 21:47:03 +03:00
Antony Polukhin
5b53815408 Update Jamfile.v2 2020-08-27 16:34:31 +03:00
Antony Polukhin
98bf98e0a4 Update Jamfile.v2 2020-08-27 16:18:16 +03:00
Antony Polukhin
21f08e5654 allow classic and loophole reflection for MSVC 2020-08-27 12:10:02 +03:00
Antony Polukhin
9d831ab09f run tests on MSVC 2019 2020-08-27 11:57:10 +03:00
108 changed files with 2647 additions and 4002 deletions

View File

@@ -103,32 +103,29 @@ before_install:
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
- IGNORE_COVERAGE=''
# Explicitly remove the following library from Boost. This may be useful, if you're for example running Travis
# Explicitly remove the following library from Boost and use the folder for tests. This may be usefull, if you're for example running Travis
# from `Boost.DLL` repo, while Boost already has `dll`.
#
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
# By default is eaual to - BOOST_LIBS_FOLDER=$(basename $TRAVIS_BUILD_DIR)
# This will force to use local repo content, instead of the Boost's default.
- BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
- BOOST_LIBS_FOLDER=pfr #$(basename $TRAVIS_BUILD_DIR)
# Global options for sanitizers
- UBSAN_OPTIONS=print_stacktrace=1
- LSAN_OPTIONS=verbosity=1:log_threads=1
# Set this to the name of the library
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
# Cloning minimal set of Boost libraries
- BOOST=$HOME/boost-local
- echo "Testing $PROJECT_TO_TEST, to remove $BOOST/libs/$BOOST_REMOVE, testing branch $BOOST_BRANCH"
- echo "Testing $BOOST_LIBS_FOLDER, to remove $BOOST/libs/$BOOST_LIBS_FOLDER, testing branch $BOOST_BRANCH"
- git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git $BOOST
- cd $BOOST
- git submodule update --init --depth 10 tools/build tools/boostdep libs/type_index # DIFF: Added libs/type_index
- git submodule update --init --depth 10 tools/build tools/boostdep
# Replacing Boost module with this project and installing Boost dependencies
- rm -rf $BOOST/libs/$BOOST_REMOVE
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$PROJECT_TO_TEST
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" $(basename $TRAVIS_BUILD_DIR)
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" type_index # DIFF: Added line
- rm -rf $BOOST/libs/$BOOST_LIBS_FOLDER
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$BOOST_LIBS_FOLDER
- TRAVIS_BUILD_DIR=$BOOST/libs/$BOOST_LIBS_FOLDER
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" -I example -I examples $(basename $TRAVIS_BUILD_DIR)
- git status
# Adding missing toolsets and preparing Boost headers
@@ -145,7 +142,7 @@ before_install:
echo "using clang : 8 : clang++-8 ;" >> ~/user-config.jam
echo "using clang : 10 : clang++-10 ;" >> ~/user-config.jam
echo "using clang : libc++ : clang++-libc++ ;" >> ~/user-config.jam
- cd $BOOST/libs/$PROJECT_TO_TEST/test/
- cd $BOOST/libs/$BOOST_LIBS_FOLDER/test/
script:
- sh -c "../../../b2 -j2 $B2_ARGS"
@@ -159,7 +156,7 @@ after_success:
- find ../../../bin.v2/ -name "*.no" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- wget https://github.com/linux-test-project/lcov/archive/v1.12.zip
- unzip v1.12.zip
- LCOV="`pwd`/lcov-1.12/bin/lcov --gcov-tool gcov-6"
- LCOV="`pwd`/lcov-1.12/bin/lcov"
# Preparing Coveralls data by changind data format to a readable one
- echo "$LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info"
@@ -167,10 +164,10 @@ after_success:
# ... erasing /test/ /example/ folder data
- cd $BOOST
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$BOOST_LIBS_FOLDER/test/*" $IGNORE_COVERAGE "*/$BOOST_LIBS_FOLDER/tests/*" "*/$BOOST_LIBS_FOLDER/examples/*" "*/$BOOST_LIBS_FOLDER/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing data that is not related to this project directly
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$PROJECT_TO_TEST\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$BOOST_LIBS_FOLDER\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- echo $OTHER_LIBS
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"

23
LICENSE_1_0.txt Normal file
View File

@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@@ -1,6 +1,6 @@
# Precise and Flat Reflection (ex Magic Get, ex PODs Flat Reflection)
# Boost.PFR
This C++14 library is meant for accessing structure elements by index and providing other std::tuple like methods for user defined types without any macro or boilerplate code.
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.
[Latest documentation](http://apolukhin.github.com/magic_get/index.html)
@@ -9,26 +9,32 @@ This C++14 library is meant for accessing structure elements by index and provid
Branches | Build | Tests coverage | More info
----------------|-------------- | -------------- |-----------
Develop: | [![Build Status](https://travis-ci.org/apolukhin/magic_get.svg?branch=develop)](https://travis-ci.org/apolukhin/magic_get) [![Build status](https://ci.appveyor.com/api/projects/status/1edm74h5id8qpr2k/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/magic-get/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...](http://www.boost.org/development/tests/develop/developer/pfr.html)) -->
Master: | [![Build Status](https://travis-ci.org/apolukhin/magic_get.svg?branch=master)](https://travis-ci.org/apolukhin/magic_get) [![Build status](https://ci.appveyor.com/api/projects/status/1edm74h5id8qpr2k/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/magic-get/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...](http://www.boost.org/development/tests/master/developer/pfr.html)) -->
Develop: | [![Build Status](https://travis-ci.org/apolukhin/magic_get.svg?branch=develop)](https://travis-ci.org/apolukhin/magic_get) [![Build status](https://ci.appveyor.com/api/projects/status/3tled9gd24k9paia/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/magic-get/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...](http://www.boost.org/development/tests/develop/developer/pfr.html)
Master: | [![Build Status](https://travis-ci.org/apolukhin/magic_get.svg?branch=master)](https://travis-ci.org/apolukhin/magic_get) [![Build status](https://ci.appveyor.com/api/projects/status/3tled9gd24k9paia/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/magic-get/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...](http://www.boost.org/development/tests/master/developer/pfr.html)
### Motivating Example #0
```c++
// requires: C++14
#include <iostream>
#include <fstream>
#include <string>
#include "boost/pfr/precise.hpp"
#include "boost/pfr.hpp"
struct some_person {
std::string name;
unsigned birth_year;
std::string name;
unsigned birth_year;
};
int main() {
some_person val{"Edgar Allan Poe", 1809};
int main(int argc, const char* argv[]) {
some_person val{"Edgar Allan Poe", 1809};
std::cout << boost::pfr::get<0>(val) // No macro!
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate initializables!
std::cout << boost::pfr::get<0>(val) // No macro!
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate initializables!
if (argc > 1) {
std::ofstream ofs(argv[1]);
ofs << boost::pfr::io(val); // File now contains: {"Edgar Allan Poe", 1809}
}
}
```
Outputs:
@@ -39,7 +45,6 @@ Edgar Allan Poe was born in 1809
### Motivating Example #1
```c++
// requires: C++14
#include <iostream>
#include "boost/pfr/precise.hpp"
@@ -50,11 +55,9 @@ struct my_struct { // no ostream operator defined!
};
int main() {
using namespace boost::pfr::ops; // out-of-the-box ostream operator for all PODs!
my_struct s{100, 'H', 3.141593};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
<< " fields: " << boost::pfr::io(s) << "\n";
}
```
@@ -67,7 +70,6 @@ my_struct has 3 fields: {100, H, 3.14159}
### Motivating Example #2
```c++
// requires: C++14
#include <iostream>
#include "boost/pfr/precise.hpp"
@@ -77,11 +79,9 @@ struct my_struct { // no ostream operator defined!
};
int main() {
using namespace boost::pfr::ops; // out-of-the-box ostream operators for aggregate initializables!
my_struct s{{"Das ist fantastisch!"}, 100};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
<< " fields: " << boost::pfr::io(s) << "\n";
}
```
@@ -94,10 +94,7 @@ my_struct has 2 fields: {"Das ist fantastisch!", 100}
### Requirements and Limitations
General:
* C++14 compatible compiler (GCC-5.0+, Clang, Visual Studio 2017 with /std:c++latest or /std:c++17, ...)
* Static variables are ignored
* T must be constexpr aggregate initializable and must not contain references nor bitfields
[See docs](http://apolukhin.github.com/magic_get/index.html).
### License

View File

@@ -30,50 +30,29 @@ local doxygen_params =
<doxygen:param>INLINE_SIMPLE_STRUCTS=YES
<doxygen:param>SORT_MEMBER_DOCS=NO
<doxygen:param>"ALIASES= \\
\"flattening{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.tutorial.flattening'>\\1</link>\\endxmlonly\" \\
\"podops=\\b See \\b Also: \\xmlonly<link linkend='boost_precise_and_flat_reflectio.tutorial.three_ways_of_getting_operators'>Three ways of getting operators</link>\\endxmlonly\" \\
\"constexprinit{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.requirements_and_limitations'>\\1</link>\\endxmlonly\" \\
\"rcast=\\b Note: If reflecting structures with enums may `reinterpret_cast` enum to a reference to underlying type.\" \\
\"flatpod{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.requirements_and_limitations'>\\1</link>\\endxmlonly\" \\
\"forcedlink{1}=\\xmlonly<link linkend='boost.pfr.\\1'>\\endxmlonly boost::pfr::\\1\\xmlonly</link>\\endxmlonly\" \\
\"podops=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.three_ways_of_getting_operators'>\\endxmlonly 'Three ways of getting operators' \\xmlonly</link>\\endxmlonly\" \\
\"customio=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.custom_printing_of_aggregates'>\\endxmlonly 'Custom printing of aggregates' \\xmlonly</link>\\endxmlonly for info on how to implement your own manipulator with custom format.\" \\
\"aggregate=\\xmlonly<link linkend='boost_pfr.limitations_and_configuration'>\\endxmlonly simple aggregate \\xmlonly</link>\\endxmlonly\" \\
\"BOOST_PFR_DOXYGEN_INVOKED\" \\
"
;
doxygen autodoc_all
doxygen autodoc_pfr
:
[ glob ../../../boost/pfr.hpp ]
[ glob ../../../boost/pfr/*.hpp ]
:
$(doxygen_params)
<xsl:param>"boost.doxygen.reftitle=Include all"
;
doxygen autodoc_flat
:
[ glob ../../../boost/pfr/flat.hpp ]
[ glob ../../../boost/pfr/flat/*.hpp ]
:
$(doxygen_params)
<xsl:param>"boost.doxygen.reftitle=Flat Reflection"
;
doxygen autodoc_precise
:
[ glob ../../../boost/pfr/precise.hpp ]
[ glob ../../../boost/pfr/precise/*.hpp ]
:
$(doxygen_params)
<xsl:param>"boost.doxygen.reftitle=Precise Reflection"
<xsl:param>"boost.doxygen.reftitle=Reference Section"
;
boostbook pfr-doc
:
pfr.qbk
:
<dependency>autodoc_all
<dependency>autodoc_precise
<dependency>autodoc_flat
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_63_0
<dependency>autodoc_pfr
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_72_0
#<xsl:param>boost.root=../../../.
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
;

View File

@@ -1,6 +1,6 @@
[library Boost.PFR
[quickbook 1.6]
[version 1.0]
[version 2.0]
[copyright 2016-2020 Antony Polukhin]
[category Language Features Emulation]
[license
@@ -10,298 +10,402 @@
]
]
[section Motivation]
[section Intro]
In C++ we have:
Boost.PFR is a C++14 library for a very basic reflection. It gives you access to structure elements by index and provides other `std::tuple` like methods for user defined types without macro or boilerplate code:
* tuples - types that provide access to members by index. Those are useful for generic programming.
* structures - types with named fields that do not provide access to members by index. Those are just easy to use.
[import ../example/motivating_example0.cpp]
[pfr_motivating_example]
This library provides tuple like methods for aggregate initializable structures, making them usable in contexts where only tuples were useful.
[note All you have to do is to add `#include <boost/pfr.hpp>`.
No macro or other type/member registrations required.]
See [link boost_pfr.limitations_and_configuration [*limitations]].
[import ../example/examples.cpp]
[h2 Usecase example]
The two different types of reflection are:
Imagine that you are writing the wrapper library for a database. Depending on the usage of Boost.PFR users code will look differently:
* [*Precise] reflection, where each field type is represented as it actually exists, even if the type is itself a user-defined type.
* [*Flat] reflection, where user-defined types are represented by their individual field types, and all other types are represented as they actually exists.
[table:hand_made_vs_pfr_1
[[ Without Boost.PFR ] [ With Boost.PFR ]]
[[
```
#include <db/api.hpp>
As an example:
struct user_info {
std::int64_t id;
std::string name, email, login;
};
[pfr_intro]
user_info retrieve_friend(std::string_view name) {
std::tuple info_tuple
= db::one_row_as<std::int64_t, std::string, std::string, std::string>(
"SELECT id, name, email, login FROM user_infos WHERE name=$0",
name
);
////////////////////////////////////////////////////////////////////////////////
user_info info {
std::move(std::get<0>(info_tuple)),
std::move(std::get<1>(info_tuple)),
std::move(std::get<2>(info_tuple)),
std::move(std::get<3>(info_tuple)),
}
////////////////////////////////////////////////////////////////////////////////
auto friend_info = ask_user_for_friend(std::move(info));
db::insert(
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
std::move(friend_info.id), //////////////////////////////////////////////
std::move(friend_info.name), // Users are forced to move individual fields
std::move(friend_info.email), // because your library can not iterate over
std::move(friend_info.login) // the fields of a user provided structure
);
return friend_info;
}
```
][
```
#include <db/api.hpp>
struct user_info {
std::int64_t id;
std::string name, email, login;
};
user_info retrieve_friend(std::string_view name) {
// With Boost.PFR you can put data directly into user provided structures
user_info info = db::one_row_as<user_info>(
"SELECT id, name, email, login FROM user_infos WHERE name=$0",
name
);
////////////////// No boilerplate code to move data around /////////////////////
Boost.Precise and Flat Reflection (Boost.PFR) adds following out-of-the-box functionality for aggregate initializable structures:
* comparison operators
////////////////////////////////////////////////////////////////////////////////
auto friend_info = ask_user_for_friend(std::move(info));
db::insert(
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
friend_info ////////////////////////////////////////////////////////////
// Boost.PFR allows you to iterate over all the fields of a
// user provided structure
//
);
return friend_info;
}
```
]]
]
Otherwise your library could require a customization point for a user type:
[table:hand_made_vs_pfr_2
[[ Without Boost.PFR ] [ With Boost.PFR ]]
[[
```
#include <db/api.hpp>
struct user_info {
std::int64_t id;
std::string name, email, login;
};
/// Customizations via hand-written code or macro like BOOST_FUSION_ADAPT_STRUCT ///
auto db_api_tie(user_info& ui) noexcept {
return std::tie(ui.id, ui.name, ui.email, ui.login);
}
auto db_api_tie(const user_info& ui) noexcept {
return std::tie(ui.id, ui.name, ui.email, ui.login);
}
////////////////////////////////////////////////////////////////////////////////////
```
][
```
#include <db/api.hpp>
struct user_info {
std::int64_t id;
std::string name, email, login;
};
//////// With Boost.PFR there's no need in hand written customizations /////////////
////////////////////////////////////////////////////////////////////////////////////
```
]]
]
With Boost.PFR the code is shorter, more readable and more pleasant to write.
[h2 Out of the box functionality ]
Boost.PFR adds the following out-of-the-box functionality for aggregate initializable structures:
* comparison functions
* heterogeneous comparators
* hash
* stream operators
* IO streaming
* access to members by index
* member reflections
* member type retrieval
* methods for cooperation with `std::tuple`
* methods to visit each field of the structure
PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder [@https://github.com/apolukhin/magic_get from the github] into your project, and the library would work fine.
Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder [@https://github.com/boostorg/pfr from the github] into your project, and the library will work fine.
[warning This is not an official Boost library! It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library to formal review, if community think that it is interesting!]
[caution Recommended C++ Standards are C++17 and above]
[caution Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
[endsect]
[section Short Examples for the Impatient]
Examples in the table use the following definition:
[import ../example/quick_examples.cpp]
[pfr_quick_examples_structures]
[table:quick_examples
[[ Code snippet ] [ `var` content or output ] [ Function description: ]]
[[ Code snippet ] [ Reference: ]]
[
[ [pfr_quick_examples_get_1] ]
[ `var == {A {1, 2.0}}` ]
[ [funcref boost::pfr::get get] ]
][
[ [pfr_quick_examples_flat_get_1] ]
[ `var == {A, {1, 3.14159}}` ]
[ [funcref boost::pfr::flat_get flat_get] ]
][
[ [pfr_quick_examples_get_2] ]
[ `var == {A, {777, 42.01}}` ]
[ [funcref boost::pfr::get get] ]
][
[ [pfr_quick_examples_flat_get_2] ]
[ `var == {A, {777, 42.01}}` ]
[ [funcref boost::pfr::flat_get flat_get] ]
][
[ [pfr_quick_examples_flat_functors_uset] ]
[ `my_uset` constains `var` ]
[
[classref boost::pfr::flat_hash flat_hash]
[classref boost::pfr::flat_equal_to flat_equal_to]
]
][
[ [pfr_quick_examples_flat_functors_set] ]
[ `my_set` constains `var` ]
[ [classref boost::pfr::flat_less flat_less] ]
][
[ [pfr_quick_examples_flat_ops] ]
[ assert succeeds ]
[ [headerref boost/pfr/flat/ops.hpp using\u00A0namespace\u00A0flat_ops;] ]
[ [pfr_quick_examples_get] ]
[ [funcref boost::pfr::get] ]
][
[ [pfr_quick_examples_ops] ]
[ assert succeeds ]
[ [headerref boost/pfr/precise/ops.hpp using\u00A0namespace\u00A0ops;] ]
][
[ [pfr_quick_examples_flat_for_each] ]
[ `var == {B, {778, 4.14159}}` ]
[ [funcref boost::pfr::flat_for_each_field flat_for_each_field] ]
[
[headerref boost/pfr/ops.hpp Header boost/pfr/ops.hpp]:
* [funcref boost::pfr::eq]
* [funcref boost::pfr::ne]
* [funcref boost::pfr::gt]
* ...
]
][
[ [pfr_quick_examples_for_each] ]
[ `var == {B, {787, 103.142}}` ]
[ [funcref boost::pfr::for_each_field for_each_field] ]
[
[funcref boost::pfr::for_each_field]
[funcref boost::pfr::io]
]
][
[ [pfr_quick_examples_flat_for_each_idx] ]
[ ```0: char
1: int
2: double
``` ]
[ [funcref boost::pfr::flat_for_each_field flat_for_each_field] ]
[ [pfr_quick_examples_functions_for] ]
[ [macroref BOOST_PFR_FUNCTIONS_FOR] ]
][
[ [pfr_quick_examples_eq_fields] ]
[
[headerref boost/pfr/ops_fields.hpp Header boost/pfr/ops_fields.hpp ]:
* [funcref boost::pfr::eq_fields]
* [funcref boost::pfr::ne_fields]
* [funcref boost::pfr::gt_fields]
* ...
[headerref boost/pfr/io_fields.hpp Header boost/pfr/io_fields.hpp ]
* [funcref boost::pfr::io_fields]
]
][
[ [pfr_quick_examples_for_each_idx] ]
[ ```0: char
1: quick_examples_ns::foo
``` ]
[ [funcref boost::pfr::for_each_field for_each_field] ]
[ [funcref boost::pfr::for_each_field] ]
][
[ [pfr_quick_examples_tuple_size] ]
[ `tuple_size: 2` ]
[ [classref boost::pfr::tuple_size tuple_size] ]
][
[ [pfr_quick_examples_flat_tuple_size] ]
[ `flat_tuple_size: 3` ]
[ [classref boost::pfr::flat_tuple_size flat_tuple_size] ]
[ [classref boost::pfr::tuple_size] ]
][
[ [pfr_quick_examples_structure_to_tuple] ]
[ `var == {A, {777, 3.14159}}` ]
[ [funcref boost::pfr::structure_to_tuple structure_to_tuple] ]
][
[ [pfr_quick_examples_flat_structure_to_tuple] ]
[ `var == {A, {777, 3.14159}}` ]
[ [funcref boost::pfr::flat_structure_to_tuple flat_structure_to_tuple] ]
[ [funcref boost::pfr::structure_to_tuple] ]
][
[ [pfr_quick_examples_structure_tie] ]
[ `var == {A, {1, 2.0}}` ]
[ [funcref boost::pfr::structure_tie structure_tie] ]
][
[ [pfr_quick_examples_flat_structure_tie] ]
[ `var == {C, {777, 3.14159}}` ]
[ [funcref boost::pfr::flat_structure_tie flat_structure_tie] ]
[ [funcref boost::pfr::structure_tie] ]
]]
[endsect]
[section Tutorial]
[section Accessing structure member by index] [pfr_example_get] [endsect]
[section Flattening] [pfr_example_flattening] [pfr_example_flattening_2] [endsect]
[/ [section Counting fields] [pfr_example_tuple_size] [endsect] ]
[import ../example/sample_printing.cpp]
[import ../example/get.cpp]
[section Flat or Precise functions to choose]
All the functions that have `flat_` prefix and are declared in `boost/pfr/flat/*` headers are the [*flat] functions, other function are [*precise] and are declared in `boost/pfr/precise/*`. In previous example you've seen how the the flattening works.
Use [*flat] functions if you:
[section Why tuples are bad and aggregates are more preferable?]
* wish types flattened
* or you reflect types with C arrays
`std::tuple` and `std::pair` are good for generic programming, however they have disadvantages. First of all, code that uses them becomes barely readable. Consider two definitions:
For all the other cases prefer [*precise] functions.
[table:tuples_vs_aggregates
[[ Tuple ] [ Aggregate ]]
[[
```
using auth_info_tuple = std::tuple<
std::int64_t, // What does this integer represents?
std::int64_t,
std::time_t
>;
```
][
```
struct auth_info_aggregate {
std::int64_t user_id; // Oh, now I see!
std::int64_t session_id;
std::time_t valid_till;
};
```
]]
]
[warning MSVC currently supports only [*precise] functions and only in /std:c++latest or /std:c++17 modes.]
Definition via aggregate initializable structure is much more clear. Same story with usages: `return std::get<1>(value);` vs. `return value.session_id;`.
Another advantage of aggregates is a more efficient copy, move construction and assignments.
Because of the above issues some guidelines recommend to [*use aggregates instead of tuples]. However aggregates fail when it comes to the functional like programming.
Boost.PFR library [*provides tuple like methods for aggregate initializable structures], making aggregates usable in contexts where only tuples were useful.
[endsect]
[section Accessing structure member by index] [pfr_example_get] [endsect]
[section Custom printing of aggregates] [pfr_sample_printing] [endsect]
[section Three ways of getting operators ]
There are three ways to start using Boost.PFR hashing, comparison and streaming operators for type `T` in your code. Each method has it's own drawbacks and suits own cases.
There are three ways to start using Boost.PFR hashing, comparison and streaming for type `T` in your code. Each method has its own drawbacks and suits own cases.
[table:flat_ops_comp Different approaches for operators
[table:ops_comp Different approaches for operators
[[ Approach
][ Defines operators in global namespace ][ Defined operators could be found by ADL ][ Works for local types ][ Usable locally, without affecting code from other scopes ][ Ignores implicit conversion operators ][ Respects user defined operators ]]
][ When to use
][ Operators could be found by ADL ][ Works for local types ][ Usable locally, without affecting code from other scopes ][ Ignores implicit conversion operators ][ Respects user defined operators ]]
[[
[headerref boost/pfr/precise/ops.hpp using\u00A0namespace\u00A0boost::pfr::ops;]
[headerref boost/pfr/ops.hpp boost/pfr/ops.hpp: eq, ne, gt, lt, le, ge]
[headerref boost/pfr/flat/ops.hpp using\u00A0namespace\u00A0boost::pfr::flat_ops;]
][ no ][ no ][ yes ][ yes ][ no ][ yes ]]
[headerref boost/pfr/io.hpp boost/pfr/io.hpp: io]
][
Use when you need to compare values by provided for them operators or via field-by-field comparison.
][ no ][ yes ][ yes ][ no ][ yes ]]
[[
[macroref BOOST_PFR_FLAT_FUNCTIONS_FOR]
[macroref BOOST_PFR_PRECISE_FUNCTIONS_FOR]
][ yes if T is in it ][ yes ][ no ][ no, but could be limited to translation unit ][ yes for T ] [ no (compile time error) ]]
[macroref BOOST_PFR_FUNCTIONS_FOR BOOST_PFR_FUNCTIONS_FOR(T)]
][
Use near the type definition to define the whole set of operators for your type.
][ yes ][ no ][ no ][ yes for T ] [ no (compile time error) ]]
[[
[headerref boost/pfr/flat/global_ops.hpp]
[headerref boost/pfr/ops_fields.hpp boost/pfr/ops_fields.hpp: eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields]
[headerref boost/pfr/precise/global_ops.hpp]
][ yes ][ yes ][ yes ][ no, but could be limited to translation unit ][ yes all ][ yes ]]
[headerref boost/pfr/io.hpp boost/pfr/io_fields.hpp: io_fields]
][
Use to implement the required set of operators for your type.
][ no ][ yes ][ yes ][ yes ][ yes ]]
]
More detailed description follows:
[*1. [headerref boost/pfr/precise/ops.hpp `using namespace boost::pfr::ops;`] and [headerref boost/pfr/flat/ops.hpp `using namespace boost::pfr::flat_ops;`] approach]
[*1. `eq, ne, gt, lt, le, ge, io` approach]
This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there's no operators defined for the type:
This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there are no operators defined for the type:
```
#include <boost/pfr/precise/ops.hpp>
#include <boost/pfr/ops.hpp>
template <class T>
struct uniform_comparator_less {
bool operator()(const T& lhs, const T& rhs) const noexcept {
using namespace boost::pfr::ops; // Enables Boost.PFR operators usage in this scope.
// If T has operator< or conversion operator then will use it.
// Otherwise will use boost::pfr::flat_less<T>.
return lhs < rhs;
// If T has operator< or conversion operator then it is used.
return boost::pfr::lt(lhs, rhs);
}
};
```
This method's effects are local to the function. It works even for local types, like structures defined in functions.
However *Argument Dependant Lookup* does not work with it:
This methods effects are local to the function. It works even for local types, like structures defined in functions.
```
#include <boost/pfr/flat/ops.hpp>
template <class T>
struct uniform_comparator_less {
bool operator()(const T& lhs, const T& rhs) const noexcept {
using namespace flat_ops;
// Compile time error if T has neither operator< nor
// conversion operator to comparable type.
return std::less{}(lhs, rhs);
}
};
```
[*2. [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR] and [macroref BOOST_PFR_PRECISE_FUNCTIONS_FOR] approach]
[*2. BOOST_PFR_FUNCTIONS_FOR(T) approach]
This method is good if you're writing a structure and wish to define operators for that structure.
```
#include <boost/pfr/flat/functions_for.hpp>
#include <boost/pfr/functions_for.hpp>
struct pair_like {
int first;
short second;
};
BOOST_PFR_FLAT_FUNCTIONS_FOR(pair_like) // Defines operators
BOOST_PFR_FUNCTIONS_FOR(pair_like) // Defines operators
// ...
assert(pair_like{1, 2} < pair_like{1, 3});
```
Argument Dependant Lookup works well, `std::less` will find the operators for `struct pair_like`. [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR BOOST_PFR_FLAT_FUNCTIONS_FOR(T)]
can not be used for local types, it must be called only once in namespace of `T`. It does not respect conversion operators of `T`, so for example the following code
Argument Dependant Lookup works well. `std::less` will find the operators for `struct pair_like`. [macroref BOOST_PFR_FUNCTIONS_FOR BOOST_PFR_FUNCTIONS_FOR(T)]
can not be used for local types. It does not respect conversion operators of `T`, so for example the following code
will output different values:
```
#include <boost/pfr/flat/functions_for.hpp>
#include <boost/pfr/functions_for.hpp>
struct empty {
operator std::string() { return "empty{}"; }
};
// Uncomment to get different output:
// BOOST_PFR_FLAT_FUNCTIONS_FOR(empty)
// BOOST_PFR_FUNCTIONS_FOR(empty)
// ...
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FLAT_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
```
[*3. [headerref boost/pfr/flat/global_ops.hpp] and [headerref boost/pfr/precise/global_ops.hpp] approach]
[*3. `eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields, io_fields` approach]
This approach is for those, who wish to have comparisons/streaming/hashing for all their types.
This method is good if you're willing to provide only some operators for your type:
```
#include <boost/pfr/flat/global_ops.hpp>
#include <boost/pfr/io_fields.hpp>
struct pair_like {
int first;
short second;
std::string second;
};
// ...
assert(pair_like{1, 2} < pair_like{1, 3});
inline std::ostream& operator<<(std::ostream& os, const pair_like& x) {
return os << bost::pfr::io_fields(x);
}
```
Argument Dependant Lookup works well, `std::less` will find the operators for `struct pair_like`. Operators for local types will be also defined.
*All conversion operators of types are not used during comparisons/streaming/hashing.*
All the `*_fields` functions do ignore user defined operators and work only with fields of a type. This makes them perfect for defining you own operators.
[endsect]
[section Reflection of unions ]
With [*precise] reflection you could do reflection if a type contains union. But be sure that operations for union are manually defined:
You could use tuple-like representation if a type contains union. But be sure that operations for union are manually defined:
```
#include <boost/pfr/precise/ops.hpp>
#include <boost/pfr/ops.hpp>
union test_union {
int i;
@@ -310,18 +414,13 @@ union test_union {
inline bool operator==(test_union l, test_union r) noexcept; // Compile time error without this operator
struct foo { int i; test_union u; };
bool some_function(foo f1, foo f2) {
using namespace boost::pfr::ops;
return f1 == f2; // OK
bool some_function(test_union f1, test_union f2) {
return boost::pfr::eq(f1, f2); // OK
}
```
[*Flat] reflection of types that contain unions is disabled.
[*Flat] and [*precise] reflection of unions is disabled for safety reasons. There's a way to reflect the first member of a union and use it. Unfortunately there's no way to find out [*active] member of a union. Accessing an inactive union member is an Undefined Behavior. Using the first union member for reflection could lead to disaster if it is some character pointer. For example ostreaming `union {char* c; long long ll; } u; u.ll= 1;` will crash your program, as the active member is `ll` that holds `1` but we are trying to output a `char*`. This would cause an invalid pointer2 dereference.
Reflection of unions is disabled in the Boost.PFR library for safety reasons. Alas, there's no way to find out [*active] member of a union and accessing an inactive member is an Undefined Behavior. For example, library could always return the first member, but ostreaming `u` in `union {char* c; long long ll; } u; u.ll= 1;` will crash your program with an invalid pointer dereference.
Any attempt to reflect unions leads to a compile time error. In many cases a static assert is triggered that outputs the following message:
@@ -334,37 +433,55 @@ error: static_assert failed "====================> Boost.PFR: For safety reasons
[endsect]
[section Configuration Macro]
[section Limitations and Configuration]
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
Boost.PFR library works with types that satisfy the requirements of `SimpleAggregate`: aggregate types without base classes, `const` fields, references, or C arrays:
```
struct simple_aggregate { // SimpleAggregate
std::string name;
int age;
boost::uuids::uuid uuid;
};
struct empty { // SimpleAggregate
};
struct aggregate : empty { // not a SimpleAggregate
std::string name;
int age;
boost::uuids::uuid uuid;
};
```
The library may work with aggregates that don't satisfy the requirements of `SimpleAggregate`, but the behavior tends to be non-portable.
[h2 Configuration Macro]
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
[table:linkmacro Macros
[[Macro name] [Effect]]
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to use structured bindings and other C++17 features for reflection. Define to `0` otherwize.]]
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` otherwize.]]
[[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use PFR version of that metafunction. Define to `1` otherwize. ]]
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to override Boost.PFR choice and use C++17 structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++17 structured bindings usage.]]
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]]
[[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use Boost.PFR version of that metafunction. Define to `1` to override Boost.PFR detection logic. ]]
]
Note that disabling [*Loophole] in C++14 significantly limits the reflection abilities of the library. See next section for more info.
[h2 Details on Limitations]
[endsect]
[section Limitations]
The reflection has some limitations that depend on a C++ Standard and compiler capabilities:
The Boost.PFRs reflection has some limitations that depend on a C++ Standard and compiler capabilities:
* Static variables are ignored
* T must be aggregate initializable
* Additional C++14 [*only] limitations (switch to C++17 to remove all of those):
* T must be aggregate initializable without empty base classes
* if T contains C arrays or it is inherited from non-empty type then the result of reflection may differ depending on the C++ version and library configuration
* Additional limitations if [*BOOST_PFR_USE_CPP17 == 0]:
* Non of the member fields should have a template constructor from one parameter.
* Additional limitations if the [*Loophole] as also disabled:
* [*Flat]:
* T must be POD and must not contain references nor bitfields
* Enums will be returned as their underlying type
* [*Precise]:
* T must be constexpr aggregate initializable and all it's fields must be constexpr default constructible
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/precise/core.hpp boost::pfr::tuple_element] require T to be a flat POD type
* Additional limitations if [*BOOST_PFR_USE_LOOPHOLE == 0]:
* T must be constexpr aggregate initializable and all its fields must be constexpr default constructible
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/core.hpp boost::pfr::tuple_element] require T to be a POD type with built-in types only.
[endsect]
@@ -372,48 +489,42 @@ The reflection has some limitations that depend on a C++ Standard and compiler c
Short description:
* Flat functions:
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
# at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
# at run-time: get pointer to each field, knowing the structure address and each field offset
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
* Precise functions:
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
* C++17:
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
* C++14:
# Same approach as with [*flat] functions
* C++14 with disabled [*Loophole]:
# at compile-time: use flat reflection if it could precisely reflect the type. Otherwise:
# at compile-time: let `I` be is an index of current field, it equals 0
# at run-time: `T` is constructed and field `I` is aggregate initialized using a separate instance of structure that is convertible to anything [note Additional care is taken to make sure that all the information about `T` is available to the compiler and that operations on `T` have no side effects, so the compiler can optimize away the unnecessary temporary objects.]
# at compile-time: `I += 1`
# at compile-time: if `I` does not equal fields count goto step [~c.] from inside of the conversion operator of the structure that is convertible to anything
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
# at run-time: get pointer to each field, knowing the structure address and each field offset
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
* [*BOOST_PFR_USE_CPP17 == 1]:
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
* [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 1]:
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
# at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
# at run-time: get pointer to each field, knowing the structure address and each field offset
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
* [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 0]:
# at compile-time: let `I` be is an index of current field, it equals 0
# at run-time: `T` is constructed and field `I` is aggregate initialized using a separate instance of structure that is convertible to anything [note Additional care is taken to make sure that all the information about `T` is available to the compiler and that operations on `T` have no side effects, so the compiler can optimize away the unnecessary temporary objects.]
# at compile-time: `I += 1`
# at compile-time: if `I` does not equal fields count goto step [~c.] from inside of the conversion operator of the structure that is convertible to anything
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
# at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
# at run-time: get pointer to each field, knowing the structure address and each field offset
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
Long description of some basics: [@https://youtu.be/UlNUNxLtBI0 Antony Polukhin: Better C++14 reflections].
Long description of some basics of C++14 with disabled [*Loophole]: [@https://youtu.be/abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling].
Long description of some basics of C++14 with [link boost_pfr.limitations_and_configuration [*BOOST_PFR_USE_LOOPHOLE == 0]]: [@https://youtu.be/abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling].
Description of the [*BOOST_PFR_USE_LOOPHOLE == 1] technique by its inventor Alexandr Poltavsky [@http://alexpolt.github.io/type-loophole.html in his blog].
[endsect]
[section Acknowledgements]
Great thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/apolukhin/magic_get/issues/5 Manual type registering/structured bindings might be unnecessary].
Many thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/apolukhin/magic_get/issues/5 Manual type registering/structured bindings might be unnecessary].
Great thanks to Alexandr Poltavsky for initial implementation the [*Loophole] technique and for describing it [@http://alexpolt.github.io/type-loophole.html in his blog].
Many thanks to Alexandr Poltavsky for initial implementation the [*BOOST_PFR_USE_LOOPHOLE == 1] technique and for describing it [@http://alexpolt.github.io/type-loophole.html in his blog].
Great thanks to Chris Beck for implementing the detect-offsets-and-get-field-address functionality that avoids Undefined Behavior of reinterpret_casting layout compatible structures.
Many thanks to Chris Beck for implementing the detect-offsets-and-get-field-address functionality that avoids Undefined Behavior of reinterpret_casting layout compatible structures.
Many thanks to the Boost people who participated in the formal review, especially to Benedek Thaler, Steven Watanabe and Andrzej Krzemienski.
[endsect]
[section Reference]
[xinclude autodoc_precise.xml]
[xinclude autodoc_flat.xml]
[xinclude autodoc_all.xml]
[endsect]
[xinclude autodoc_pfr.xml]

View File

@@ -1,129 +0,0 @@
// Copyright 2016-2020 Antony Polukhin
// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
#include <cassert>
//[pfr_intro
#include <boost/pfr.hpp>
struct nested_t { char c; };
struct foo_t { int i; nested_t nested; };
static_assert(std::is_same<
boost::pfr::flat_tuple_element_t<1, foo_t>, // Flat reflection.
char // `char`, not `nested_t`!
>::value, "");
// Requires C++17 or Loophole enabled:
//<-
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE //->
static_assert(std::is_same<
boost::pfr::tuple_element_t<1, foo_t>, // Precise reflection.
nested_t
>::value, ""); //<-
#endif //->
//] [/pfr_intro]
//[pfr_example_get
/*`
The following example shows how to access structure fields by index using [funcref boost::pfr::get].
Let's define some structure:
*/
#include <boost/pfr/precise/core.hpp>
struct foo { // defining structure
int some_integer;
char c;
};
/*`
We can access fields of that structure by index:
*/
foo f {777, '!'};
auto& r1 = boost::pfr::get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer`
auto& r2 = boost::pfr::get<1>(f); // accessing field with index 1, returns reference to `foo::c`
//] [/pfr_example_get]
//[pfr_example_tuple_size
/*`
The following example shows how to count fields using [classref boost::pfr::tuple_size].
*/
#include <boost/pfr/precise/core.hpp>
struct foo2 { // defining structure
int some_integer;
char c;
short some_other_field;
};
static_assert(
boost::pfr::tuple_size<foo2>::value // returns total count of fields in `foo2`
== 3, ""
);
static_assert(
boost::pfr::tuple_size<int[100]>::value // works with arrays too!
== 100, ""
);
//] [/pfr_example_tuple_size]
//[pfr_example_flattening
/*`
[warning All the functions and metafunctions in Boost.PFR that start with `flat_` represent template parameter type as flat structure without static members! ]
Take a look at the `struct my_struct`:
*/
#include <boost/pfr/flat/core.hpp>
struct my_struct_nested { short a1; int a2; };
struct my_struct {
int a0;
static const int cvalue = 1000;
my_struct_nested nested;
short a3_a4[2];
};
/*` It will be flattened and represented as: */
struct my_struct_flat {
int a0;
short a1;
int a2;
short a3;
short a4;
};
//] [/pfr_example_flattening]
void example_get() {
//[pfr_example_flattening_2
/*`
It means, that:
*/
boost::pfr::flat_get<2>(my_struct{}); // ... will return `my_struct::my_struct_nested::a2` field.
boost::pfr::flat_get<3>(my_struct{}); // ... will return `my_struct::a3_a4[0]` field.
/*` Exactly the same story with arrays: */
int i[2][2] = {{10, 11}, {12, 13} };
const int& r = boost::pfr::flat_get<1>(i);
assert(r == 11);
//] [/pfr_example_flattening_2]
(void)r;
}
int main() {
example_get();
}

42
example/get.cpp Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2016-2020 Antony Polukhin
// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
//[pfr_example_get
/*`
The following example shows how to access structure fields by index using [funcref boost::pfr::get].
Let's define some structure:
*/
#include <boost/pfr/core.hpp>
struct foo { // defining structure
int some_integer;
char c;
};
/*`
We can access fields of that structure by index:
*/
foo f {777, '!'};
auto& r1 = boost::pfr::get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer`
auto& r2 = boost::pfr::get<1>(f); // accessing field with index 1, returns reference to `foo::c`
//] [/pfr_example_get]
int main() {
if (r1 != 777) return 1;
if (r2 != '!') return 2;
r1 = 42;
r2 = 'A';
if (r1 != 42) return 3;
if (r2 != 'A') return 4;
if (f.some_integer != 42) return 5;
if (f.c != 'A') return 6;
return 0;
}

View File

@@ -3,9 +3,12 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//[pfr_motivating_example
#include <iostream>
#include <string>
#include "boost/pfr/precise.hpp"
#include "boost/pfr.hpp"
struct some_person {
std::string name;
@@ -13,10 +16,11 @@ struct some_person {
};
int main() {
#if BOOST_PFR_USE_LOOPHOLE || BOOST_PFR_USE_CPP17
some_person val{"Edgar Allan Poe", 1809};
std::cout << boost::pfr::get<0>(val)
<< " was born in " << boost::pfr::get<1>(val);
#endif
std::cout << boost::pfr::get<0>(val) // No macro!
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate initializables!
std::cout << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809}
}
//]

View File

@@ -12,118 +12,65 @@
#include <boost/pfr.hpp>
#include <boost/type_index.hpp>
//[pfr_quick_examples_structures
struct foo {
int integer;
double real;
void operator +=(int v) {
integer += v * 10;
real += v * 100;
}
};
struct bar {
char character;
foo f;
};
bar var{'A', {777, 3.141593}};
//]
inline std::ostream& operator<<(std::ostream& os, const bar& b) {
return os << '{' << b.character << ", {" << b.f.integer << ", " << b.f.real << "}}";
}
void test_examples() {
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_functors_uset
// no `std::hash<bar>` or `bar::operator==(const bar&)` defined
std::unordered_set<
bar, boost::pfr::flat_hash<bar>,
boost::pfr::flat_equal_to<>> my_uset;
my_uset.insert(var);
//]
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_functors_set
// no `bar::operator<(const bar&)` defined
std::set<bar, boost::pfr::flat_less<>> my_set;
my_set.insert(var);
//]
}
{
//[pfr_quick_examples_flat_ops
using namespace boost::pfr::flat_ops; // Defines comparisons
assert((var < bar{'Z', {}} && var.f == foo{777, 3.141593}));
//]
std::cout << "boost::pfr::flat_structure_tie(var) :\n" << var << '\n';
}
#if BOOST_PFR_USE_CPP17
{
//[pfr_quick_examples_ops
struct test { std::string f1; std::string_view f2; };
using namespace boost::pfr::ops; // Defines comparisons
assert((test{"abc", ""} > test{"aaa", "zomg"}));
// Assert equality.
// Note that the equality operator for structure is not defined.
struct test {
std::string f1;
std::string_view f2;
};
assert(
boost::pfr::eq(test{"aaa", "zomg"}, test{"aaa", "zomg"})
);
//]
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_for_each
// incrementing each field on 1:
boost::pfr::flat_for_each_field(var, [](auto& field) {
field += 1;
});
//]
std::cout << "flat_for_each_field outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_for_each
// increments first field on 1, calls foo::operator+= for second field
//[pfr_quick_examples_for_each
// Increment each field of the variable on 1 and
// output the content of the variable.
struct test {
int f1;
long f2;
};
test var{42, 43};
boost::pfr::for_each_field(var, [](auto& field) {
field += 1;
});
//]
std::cout << "flat_for_each_field outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_for_each_idx
boost::pfr::flat_for_each_field(var, [](auto& field, std::size_t idx) {
std::cout << idx << ": "
<< boost::typeindex::type_id_runtime(field) << '\n';
});
// Outputs: {43, 44}
std::cout << boost::pfr::io(var);
//]
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_for_each_idx
boost::pfr::for_each_field(var, [](auto& field, std::size_t idx) {
std::cout << idx << ": "
<< boost::typeindex::type_id_runtime(field) << '\n';
{
//[pfr_quick_examples_for_each_idx
// Iterate over fields of a varible and output index and
// type of a variable.
struct tag0{};
struct tag1{};
struct sample {
tag0 a;
tag1 b;
};
// Outputs:
// 0: tag0
// 1: tag1
boost::pfr::for_each_field(sample{}, [](const auto& field, std::size_t idx) {
std::cout << '\n' << idx << ": "
<< boost::typeindex::type_id_runtime(field);
});
//]
}
@@ -131,96 +78,110 @@ void test_examples() {
{
//[pfr_quick_examples_tuple_size
std::cout << "tuple_size: "
<< boost::pfr::tuple_size<bar>::value << '\n';
// Getting fields count of some structure
struct some { int a,b,c,d,e; };
std::cout << "Fields count in structure: "
<< boost::pfr::tuple_size<some>::value // Outputs: 5
<< '\n';
//]
}
{
//[pfr_quick_examples_flat_tuple_size
std::cout << "flat_tuple_size: "
<< boost::pfr::flat_tuple_size<bar>::value << '\n';
{
//[pfr_quick_examples_get
// Get field by index and assign new value to that field
struct sample {
char c;
float f;
};
sample var{};
boost::pfr::get<1>(var) = 42.01f;
std::cout << var.f; // Outputs: 42.01
//]
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_get_1
boost::pfr::get<1>(var) = foo{1, 2}; // C++17 or Loophole is required
//]
std::cout << "boost::pfr::get<1>(var) outputs:\n" << var << '\n';
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_get_1
boost::pfr::flat_get<1>(var) = 1;
//]
std::cout << "boost::pfr::flat_get<1>(var) outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_get_2
boost::pfr::get<1>(var.f) = 42.01;
//]
std::cout << "boost::pfr::get<1>(var.f) outputs:\n" << var << '\n';
}
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_get_2
boost::pfr::flat_get<1>(var.f) = 42.01;
//]
std::cout << "boost::pfr::flat_get<1>(var.f) outputs:\n" << var << '\n';
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_structure_to_tuple
// C++17 or Loophole is required
// Getting a std::tuple of values from structures fields
struct foo { int a, b; };
struct other {
char c;
foo nested;
};
other var{'A', {3, 4}};
std::tuple<char, foo> t = boost::pfr::structure_to_tuple(var);
std::get<1>(t) = foo{1, 2};
assert(std::get<0>(t) == 'A');
assert(
boost::pfr::eq(std::get<1>(t), foo{3, 4})
);
//]
std::cout << "boost::pfr::structure_to_tuple(var) :\n" << var << '\n';
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_structure_to_tuple
std::tuple<char, int, double> t = boost::pfr::flat_structure_to_tuple(var);
std::get<0>(t) = 'C';
//]
std::cout << "boost::pfr::flat_structure_to_tuple(var) :\n" << var << '\n';
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_structure_tie
// C++17 or Loophole is required
// Getting a std::tuple of references to structure fields
struct foo { int a, b; };
struct other {
char c;
foo f;
};
other var{'A', {14, 15}};
std::tuple<char&, foo&> t = boost::pfr::structure_tie(var);
std::get<1>(t) = foo{1, 2};
std::cout << boost::pfr::io(var.f); // Outputs: {1, 2}
//]
std::cout << "boost::pfr::structure_tie(var) :\n" << var << '\n';
}
#endif
{
bar var{'A', {777, 3.141593}};
//[pfr_quick_examples_flat_structure_tie
std::tuple<char&, int&, double&> t = boost::pfr::flat_structure_tie(var);
std::get<0>(t) = 'C';
//]
std::cout << "boost::pfr::flat_structure_tie(var) :\n" << var << '\n';
}
} // void test_examples() {
} // void test_examples()
//[pfr_quick_examples_functions_for
// Define all the comparison and IO operators for my_structure type along
// with hash_value function.
#include <boost/pfr/functions_for.hpp>
namespace my_namespace {
struct my_structure {
int a,b,c,d,e,f,g;
// ...
};
BOOST_PFR_FUNCTIONS_FOR(my_structure)
}
//]
//[pfr_quick_examples_eq_fields
// Define only the equality and inequality operators for my_eq_ne_structure.
#include <boost/pfr/functions_for.hpp>
namespace my_namespace {
struct my_eq_ne_structure {
float a,b,c,d,e,f,g;
// ...
};
inline bool operator==(const my_eq_ne_structure& x, const my_eq_ne_structure& y) {
return boost::pfr::eq_fields(x, y);
}
inline bool operator!=(const my_eq_ne_structure& x, const my_eq_ne_structure& y) {
return boost::pfr::ne_fields(x, y);
}
}
//]
int main() {
test_examples();

View File

@@ -0,0 +1,95 @@
// Copyright 2016-2020 Antony Polukhin
// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
//[pfr_sample_printing
/*`
The following example shows how to write your own io-manipulator for printing:
*/
#include <boost/pfr/ops.hpp>
#include <ostream>
namespace my_ns {
/// Usage:
/// struct foo {std::uint8_t a, b;};
/// ...
/// std::cout << my_ns::my_io(foo{42, 22});
///
/// Output: 42, 22
template <class T>
auto my_io(const T& value);
namespace detail {
// Helpers to print individual values
template <class T>
void print_each(std::ostream& out, const T& v) { out << v; }
void print_each(std::ostream& out, std::uint8_t v) { out << static_cast<unsigned>(v); }
void print_each(std::ostream& out, std::int8_t v) { out << static_cast<int>(v); }
// Structure to keep a reference to value, that will be ostreamed lower
template <class T>
struct io_reference {
const T& value;
};
// Output each field of io_reference::value
template <class T>
std::ostream& operator<<(std::ostream& out, io_reference<T>&& x) {
const char* sep = "";
boost::pfr::for_each_field(x.value, [&](const auto& v) {
out << std::exchange(sep, ", ");
detail::print_each(out, v);
});
return out;
}
}
// Definition:
template <class T>
auto my_io(const T& value) {
return detail::io_reference<T>{value};
}
} // namespace my_ns
//] [/pfr_sample_printing]
#include <iostream>
#include <sstream>
int main() {
struct foo {std::uint8_t a, b;};
std::ostringstream oss;
oss << my_ns::my_io(foo{42, 22});
if (oss.str() != "42, 22") {
return 1;
}
struct two_big_strings {
std::string first;
std::string second;
};
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
const char* huge_string = "Some huge string that should not fit into std::string SSO."
"And by 'huge' I mean really HUGE string with multiple statements and a lot of periods........."
;
oss.str({});
oss << my_ns::my_io(two_big_strings{
huge_string, huge_string
});
if (oss.str() != huge_string + std::string(", ") + huge_string) {
return 2;
}
#endif
return 0;
}

View File

@@ -7,10 +7,15 @@
#define BOOST_PFR_HPP
/// \file boost/pfr.hpp
/// Includes all the Boost.PFR headers, except \xmlonly<link linkend='header.boost.pfr.flat.global_ops_hpp'>boost/pfr/flat/global_ops.hpp</link>\endxmlonly and \xmlonly<link linkend='header.boost.pfr.precise.global_ops_hpp'>boost/pfr/precise/global_ops.hpp</link>\endxmlonly
/// Includes all the Boost.PFR headers
#include <boost/pfr/precise.hpp>
#include <boost/pfr/flat.hpp>
#include <boost/pfr/core.hpp>
#include <boost/pfr/functions_for.hpp>
#include <boost/pfr/functors.hpp>
#include <boost/pfr/io.hpp>
#include <boost/pfr/io_fields.hpp>
#include <boost/pfr/ops.hpp>
#include <boost/pfr/ops_fields.hpp>
#include <boost/pfr/tuple_size.hpp>
#endif // BOOST_PFR_HPP

View File

@@ -3,34 +3,33 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_CORE_HPP
#define BOOST_PFR_PRECISE_CORE_HPP
#ifndef BOOST_PFR_CORE_HPP
#define BOOST_PFR_CORE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/core.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/detail/for_each_field_impl.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
#include <boost/pfr/detail/tie_from_structure_tuple.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/tuple_size.hpp>
/// \file boost/pfr/core.hpp
/// Contains all the basic tuple-like interfaces \forcedlink{get}, \forcedlink{tuple_size}, \forcedlink{tuple_element_t}, and others.
///
/// \b Synopsis:
namespace boost { namespace pfr {
/// \brief Returns reference or const reference to a field with index `I` in aggregate T.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
/// \brief Returns reference or const reference to a field with index `I` in \aggregate `val`.
///
/// \b Example:
/// \code
@@ -47,38 +46,52 @@ constexpr decltype(auto) get(const T& val) noexcept {
/// \overload get
template <std::size_t I, class T>
constexpr decltype(auto) get(T& val) noexcept {
constexpr decltype(auto) get(T& val
#if !BOOST_PFR_USE_CPP17
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
#endif
) noexcept {
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
}
#if !BOOST_PFR_USE_CPP17
/// \overload get
template <std::size_t I, class T>
constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17");
return 0;
}
#endif
/// \brief `tuple_element` has a `typedef type-of-a-field-with-index-I-in-aggregate-T type;`
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
/// \overload get
template <std::size_t I, class T>
constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = 0) noexcept {
return std::move(detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) ));
}
/// \brief `tuple_element` has a member typedef `type` that returns the type of a field with index I in \aggregate T.
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::tuple_element<0, my_structure>::type > v;
/// std::vector< boost::pfr::tuple_element<0, my_structure>::type > v;
/// \endcode
template <std::size_t I, class T>
using tuple_element = detail::sequence_tuple::tuple_element<I, decltype( ::boost::pfr::detail::tie_as_tuple(std::declval<T&>()) ) >;
/// \brief Type of a field with index `I` in aggregate `T`.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
/// \brief Type of a field with index `I` in \aggregate `T`.
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::tuple_element_t<0, my_structure> > v;
/// std::vector< boost::pfr::tuple_element_t<0, my_structure> > v;
/// \endcode
template <std::size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;
/// \brief Creates an `std::tuple` from an aggregate T.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
/// \brief Creates a `std::tuple` from fields of an \aggregate `val`.
///
/// \b Example:
/// \code
@@ -96,33 +109,67 @@ constexpr auto structure_to_tuple(const T& val) noexcept {
}
/// \brief Creates an `std::tuple` with lvalue references to fields of an aggregate T.
/// \brief std::tie` like function that ties fields of a structure.
///
/// \b Requires: C++17 or \flatpod{C++14 flat POD or C++14 with not disabled Loophole}.
/// \returns a `std::tuple` with lvalue and const lvalue references to fields of an \aggregate `val`.
///
/// \b Example:
/// \code
/// void foo(const int&, const short&);
/// struct my_struct { int i, short s; };
///
/// const my_struct const_s{1, 2};
/// std::apply(foo, structure_tie(const_s));
///
/// my_struct s;
/// structure_tie(s) = std::tuple<int, short>{10, 11};
/// assert(s.s == 11);
/// \endcode
template <class T>
constexpr auto structure_tie(T& val) noexcept {
constexpr auto structure_tie(const T& val) noexcept {
return detail::make_conststdtiedtuple_from_tietuple(
detail::tie_as_tuple(const_cast<T&>(val)),
detail::make_index_sequence< tuple_size_v<T> >()
);
}
/// \overload structure_tie
template <class T>
constexpr auto structure_tie(T& val
#if !BOOST_PFR_USE_CPP17
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
#endif
) noexcept {
return detail::make_stdtiedtuple_from_tietuple(
detail::tie_as_tuple(val),
detail::make_index_sequence< tuple_size_v<T> >()
);
}
#if !BOOST_PFR_USE_CPP17
/// \overload structure_tie
template <class T>
constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on non const non assignable type is allowed only in C++17");
return 0;
}
#endif
/// \overload structure_tie
template <class T>
constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = 0) noexcept {
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on rvalue references is forbidden");
return 0;
}
/// Calls `func` for each field of a `value`.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \param func must have one of the following signatures:
/// * any_return_type func(U&& field) // field of value is perfect forwarded to function
/// * any_return_type func(U&& field, std::size_t i)
/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \param value To each field of this variable will be the `func` applied.
///
@@ -140,7 +187,7 @@ void for_each_field(T&& value, F&& func) {
::boost::pfr::detail::for_each_field_dispatcher(
value,
[f = std::forward<F>(func)](auto&& t) mutable {
// MSVC related workaround. It's lambdas do not capture constexprs.
// MSVC related workaround. Its lambdas do not capture constexprs.
constexpr std::size_t fields_count_val_in_lambda
= boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
@@ -155,8 +202,10 @@ void for_each_field(T&& value, F&& func) {
);
}
/// \brief Create a tuple of lvalue references capable of de-structuring
/// assignment from fields of an aggregate T.
/// \brief std::tie-like function that allows assigning to tied values from aggregates.
///
/// \returns an object with lvalue references to `args...`; on assignment of an \aggregate value to that
/// object each field of an aggregate is assigned to the corresponding `args...` reference.
///
/// \b Example:
/// \code
@@ -174,4 +223,4 @@ constexpr detail::tie_from_structure_tuple<Elements...> tie_from_structure(Eleme
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_CORE_HPP
#endif // BOOST_PFR_CORE_HPP

View File

@@ -7,21 +7,32 @@
#define BOOST_PFR_DETAIL_CONFIG_HPP
#pragma once
#include <type_traits> // to get non standard platform macro definitions (__GLIBCXX__ for example)
// Reminder:
// * MSVC++ 1?.? _MSC_VER > 1900 (Visual Studio 2017)
// * MSVC++ 14.2 _MSC_VER == 1927 <- Loophole is known to work (Visual Studio ????)
// * MSVC++ 14.1 _MSC_VER == 1916 <- Loophole is known to NOT work (Visual Studio 2017)
// * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
// * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
#if defined(_MSC_VER)
# if _MSC_VER <= 1900
# error Boost.PFR library requires MSVC with c++17 support (Visual Studio 2017 or later).
# if !defined(_MSVC_LANG) || _MSC_VER <= 1900
# error Boost.PFR library requires more modern MSVC compiler.
# endif
#elif __cplusplus < 201402L
# error Boost.PFR library requires at least C++14.
#endif
#ifndef BOOST_PFR_USE_LOOPHOLE
# if !defined(__clang_major__) || __clang_major__ < 8
# if defined(_MSC_VER)
# if _MSC_VER >= 1927
# define BOOST_PFR_USE_LOOPHOLE 1
# else
# define BOOST_PFR_USE_LOOPHOLE 0
# endif
# elif defined(__clang_major__) && __clang_major__ >= 8
# define BOOST_PFR_USE_LOOPHOLE 0
# else
# define BOOST_PFR_USE_LOOPHOLE 1
# endif
#endif
@@ -29,9 +40,15 @@
#ifndef BOOST_PFR_USE_CPP17
# ifdef __cpp_structured_bindings
# define BOOST_PFR_USE_CPP17 1
# elif defined(_MSC_VER)
# warning PFR library supports MSVC compiler only with /std:c++latest or /std:c++17 flag. Assuming that you`ve used it. Define `BOOST_PFR_USE_CPP17` to 1 to suppress this warning.
# define BOOST_PFR_USE_CPP17 1
# elif defined(_MSVC_LANG)
# if _MSVC_LANG >= 201703L
# define BOOST_PFR_USE_CPP17 1
# else
# define BOOST_PFR_USE_CPP17 0
# if !BOOST_PFR_USE_LOOPHOLE
# error Boost.PFR requires /std:c++latest or /std:c++17 flags on your compiler.
# endif
# endif
# else
# define BOOST_PFR_USE_CPP17 0
# endif

View File

@@ -0,0 +1,24 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_CORE_HPP
#define BOOST_PFR_DETAIL_CORE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
// Each core provides `boost::pfr::detail::tie_as_tuple` and
// `boost::pfr::detail::for_each_field_dispatcher` functions.
//
// The whole PFR library is build on top of those two functions.
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#elif BOOST_PFR_USE_LOOPHOLE
# include <boost/pfr/detail/core14_loophole.hpp>
#else
# include <boost/pfr/detail/core14_classic.hpp>
#endif
#endif // BOOST_PFR_DETAIL_CORE_HPP

View File

@@ -1,18 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_CORE14_HPP
#define BOOST_PFR_DETAIL_CORE14_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#if BOOST_PFR_USE_LOOPHOLE
# include <boost/pfr/detail/core14_loophole.hpp>
#else
# include <boost/pfr/detail/core14_classic.hpp>
#endif
#endif // BOOST_PFR_DETAIL_CORE14_HPP

View File

@@ -508,7 +508,7 @@ constexpr auto internal_tuple_with_same_alignment() noexcept {
static_assert(
std::is_trivial<type>::value && std::is_standard_layout<type>::value,
"====================> Boost.PFR: Type can not be used is flat_ functions, because it's not POD"
"====================> Boost.PFR: Type can not be reflected without Loophole or C++17, because it's not POD"
);
static_assert(!std::is_reference<type>::value, "====================> Boost.PFR: Not applyable");
constexpr auto res = detail::as_flat_tuple_impl<type>(
@@ -528,7 +528,7 @@ struct ubiq_is_flat_refelectable {
template <class Type>
constexpr operator Type() const noexcept {
is_flat_refelectable = std::is_fundamental<Type>::value;
is_flat_refelectable = std::is_fundamental<std::remove_pointer_t<Type>>::value;
return {};
}
};
@@ -562,8 +562,6 @@ auto tie_as_flat_tuple(T& lvalue) noexcept {
return boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<tuple_type::size_v>{});
}
#if !BOOST_PFR_USE_CPP17
template <class T>
auto tie_as_tuple(T& val) noexcept {
static_assert(
@@ -572,13 +570,11 @@ auto tie_as_tuple(T& val) noexcept {
);
static_assert(
boost::pfr::detail::is_flat_refelectable<T>( detail::make_index_sequence<boost::pfr::detail::fields_count<T>()>{} ),
"====================> Boost.PFR: Not possible in C++14 to represent that type without loosing information. Use boost::pfr::flat_ version, or change type definition, or enable C++17"
"====================> Boost.PFR: Not possible in C++14 to represent that type without loosing information. Change type definition or enable C++17"
);
return boost::pfr::detail::tie_as_flat_tuple(val);
}
#endif // #if !BOOST_PFR_USE_CPP17
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////// Structure that can be converted to copy of anything
@@ -597,8 +593,6 @@ struct ubiq_constructor_constexpr_copy {
/////////////////////
#if !BOOST_PFR_USE_CPP17
template <class T, std::size_t... I>
struct is_constexpr_aggregate_initializable { // TODO: try to fix it
template <T = T{ ubiq_constructor_constexpr_copy{I}... } >
@@ -697,8 +691,6 @@ void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
);
}
#endif // #if !BOOST_PFR_USE_CPP17
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -98,7 +98,7 @@ struct loophole_ubiq_lref {
template<class U, std::size_t M, std::size_t = sizeof(loophole(tag<T,M>{})) > static char ins(int);
template<class U, std::size_t = sizeof(fn_def_lref<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)>
constexpr operator U&() const noexcept; // `const` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior.
constexpr operator U&() const&& noexcept; // `const&&` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior.
};
template <class T, std::size_t N>
@@ -107,7 +107,7 @@ struct loophole_ubiq_rref {
template<class U, std::size_t M, std::size_t = sizeof(loophole(tag<T,M>{})) > static char ins(int);
template<class U, std::size_t = sizeof(fn_def_rref<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)>
constexpr operator U&&() const noexcept; // `const` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior.
constexpr operator U&&() const&& noexcept; // `const&&` here helps to avoid ambiguity in loophole instantiations. optional_like test validate that behavior.
};
@@ -164,81 +164,6 @@ auto tie_as_tuple_loophole_impl(T& lvalue) noexcept {
);
}
// Forward declarations:
template <class T> auto tie_as_tuple_recursively(rvalue_t<T> val) noexcept;
template <class T>
auto tie_or_value(T& val, std::enable_if_t<std::is_class< std::remove_reference_t<T> >::value>* = 0) noexcept {
return boost::pfr::detail::tie_as_tuple_recursively(
boost::pfr::detail::tie_as_tuple_loophole_impl(val)
);
}
template <class T>
decltype(auto) tie_or_value(T& val, std::enable_if_t<std::is_enum<std::remove_reference_t<T>>::value>* = 0) noexcept {
// This is compatible with the pre-loophole implementation, and tests, but IIUC it violates strict aliasing unfortunately
return detail::cast_to_layout_compatible<
std::underlying_type_t<std::remove_reference_t<T> >
>(val);
#if 0
// This "works", in that it's usable and it doesn't violate strict aliasing.
// But it means we break compatibility and don't convert enum to underlying type.
return val;
#endif
}
template <class T>
auto tie_or_value(T& /*val*/, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
static_assert(
sizeof(T) && false,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
return 0;
}
template <class T>
decltype(auto) tie_or_value(T& val, std::enable_if_t<!std::is_class< std::remove_reference_t<T> >::value && !std::is_enum< std::remove_reference_t<T> >::value && !std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
return val;
}
template <class T, std::size_t... I>
auto tie_as_tuple_recursively_impl(T& tup, std::index_sequence<I...> ) noexcept
-> sequence_tuple::tuple<
decltype(boost::pfr::detail::tie_or_value(
sequence_tuple::get<I>(tup)
))...
>
{
return {
boost::pfr::detail::tie_or_value(
sequence_tuple::get<I>(tup)
)...
};
}
template <class T>
auto tie_as_tuple_recursively(rvalue_t<T> tup) noexcept {
using indexes = detail::make_index_sequence<T::size_v>;
return boost::pfr::detail::tie_as_tuple_recursively_impl(tup, indexes{});
}
template <class T>
auto tie_as_flat_tuple(T& t) {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
auto rec_tuples = boost::pfr::detail::tie_as_tuple_recursively(
boost::pfr::detail::tie_as_tuple_loophole_impl(t)
);
return boost::pfr::detail::make_flat_tuple_of_references(
rec_tuples, sequence_tuple_getter{}, size_t_<0>{}, size_t_<decltype(rec_tuples)::size_v>{}
);
}
#if !BOOST_PFR_USE_CPP17
template <class T>
auto tie_as_tuple(T& val) noexcept {
static_assert(
@@ -261,8 +186,6 @@ void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
);
}
#endif // #if !BOOST_PFR_USE_CPP17
}}} // namespace boost::pfr::detail

View File

@@ -35,7 +35,7 @@ constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = 0) noexcept {
auto& [a] = val;
auto& [a] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a);
}
@@ -48,277 +48,277 @@ constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class<
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<2>) noexcept {
auto& [a,b] = val;
auto& [a,b] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<3>) noexcept {
auto& [a,b,c] = val;
auto& [a,b,c] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<4>) noexcept {
auto& [a,b,c,d] = val;
auto& [a,b,c,d] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<5>) noexcept {
auto& [a,b,c,d,e] = val;
auto& [a,b,c,d,e] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<6>) noexcept {
auto& [a,b,c,d,e,f] = val;
auto& [a,b,c,d,e,f] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<7>) noexcept {
auto& [a,b,c,d,e,f,g] = val;
auto& [a,b,c,d,e,f,g] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<8>) noexcept {
auto& [a,b,c,d,e,f,g,h] = val;
auto& [a,b,c,d,e,f,g,h] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<9>) noexcept {
auto& [a,b,c,d,e,f,g,h,j] = val;
auto& [a,b,c,d,e,f,g,h,j] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<10>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k] = val;
auto& [a,b,c,d,e,f,g,h,j,k] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<11>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<12>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<13>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<14>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<15>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<16>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<17>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<18>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<19>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<20>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<21>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<22>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<23>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<24>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<25>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<26>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<27>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<28>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<29>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<30>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<31>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<32>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<33>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<34>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<35>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<36>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<37>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<38>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<39>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<40>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<41>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<42>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<43>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<44>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<45>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<46>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y);
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<47>) noexcept {
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z] = val;
auto& [a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z);
}
@@ -327,7 +327,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<48>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -340,7 +340,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<49>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -353,7 +353,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<50>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -366,7 +366,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<51>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -379,7 +379,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<52>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -392,7 +392,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<53>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -405,7 +405,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<54>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -418,7 +418,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<55>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -431,7 +431,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<56>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -444,7 +444,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<57>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -457,7 +457,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<58>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -470,7 +470,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<59>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -483,7 +483,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<60>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -496,7 +496,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<61>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -509,7 +509,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<62>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -522,7 +522,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<63>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -535,7 +535,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<64>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -548,7 +548,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<65>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -561,7 +561,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<66>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -574,7 +574,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<67>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -587,7 +587,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<68>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -600,7 +600,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<69>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -613,7 +613,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<70>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -626,7 +626,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<71>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -639,7 +639,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<72>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -652,7 +652,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<73>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -665,7 +665,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<74>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -678,7 +678,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<75>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -691,7 +691,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<76>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -704,7 +704,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<77>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -717,7 +717,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<78>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -730,7 +730,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<79>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -743,7 +743,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<80>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -756,7 +756,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<81>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -769,7 +769,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<82>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -782,7 +782,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<83>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -795,7 +795,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<84>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -808,7 +808,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<85>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -821,7 +821,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<86>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -834,7 +834,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<87>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -847,7 +847,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<88>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -860,7 +860,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<89>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -873,7 +873,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<90>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -886,7 +886,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<91>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -899,7 +899,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<92>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -912,7 +912,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<93>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -925,7 +925,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<94>) noexcept {
auto& [
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY,aZ
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -939,7 +939,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<95>) noexcept {
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY,aZ,
ba
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -954,7 +954,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<96>) noexcept {
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY,aZ,
ba,bb
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -969,7 +969,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<97>) noexcept {
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY,aZ,
ba,bb,bc
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -984,7 +984,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<98>) noexcept {
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY,aZ,
ba,bb,bc,bd
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -999,7 +999,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<99>) noexcept {
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY,aZ,
ba,bb,bc,bd,be
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -1014,7 +1014,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<100>) noexcept {
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
aa,ab,ac,ad,ae,af,ag,ah,aj,ak,al,am,an,ap,aq,ar,as,at,au,av,aw,ax,ay,az,aA,aB,aC,aD,aE,aF,aG,aH,aJ,aK,aL,aM,aN,aP,aQ,aR,aS,aU,aV,aW,aX,aY,aZ,
ba,bb,bc,bd,be,bf
] = val;
] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(
a,b,c,d,e,f,g,h,j,k,l,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,U,V,W,X,Y,Z,
@@ -1025,7 +1025,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<100>) noexcept {
template <class T, std::size_t I>
constexpr void tie_as_tuple(T& val, size_t_<I>) noexcept {
constexpr void tie_as_tuple(T& /*val*/, size_t_<I>) noexcept {
static_assert(sizeof(T) && false,
"====================> Boost.PFR: Too many fields in a structure T. Regenerate include/boost/pfr/detail/core17_generated.hpp file for appropriate count of fields. For example: `python ./misc/generate_cpp17.py 300 > include/boost/pfr/detail/core17_generated.hpp`");
}

View File

@@ -9,52 +9,58 @@
#include <boost/pfr/detail/config.hpp>
#include <functional>
#include <type_traits>
namespace boost { namespace pfr { namespace detail {
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
struct success{};
struct can_not_apply{};
template <template <class, class> class Detector, class Tleft, class Tright>
struct not_appliable {
static constexpr bool value = std::is_same<
Detector<Tleft, Tright>,
success
can_not_apply
>::value;
};
///////////////////// Detectors for different operators
template <class S, class T> auto comp_eq_detector_msvc_helper(long) -> decltype(std::declval<S>() == std::declval<T>());
template <class S, class T> success comp_eq_detector_msvc_helper(int);
template <class S, class T> can_not_apply comp_eq_detector_msvc_helper(int);
template <class T1, class T2> using comp_eq_detector = decltype(comp_eq_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_ne_detector_msvc_helper(long) -> decltype(std::declval<S>() != std::declval<T>());
template <class S, class T> success comp_ne_detector_msvc_helper(int);
template <class T1, class T2> using comp_ne_detector = decltype(comp_ne_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> can_not_apply comp_ne_detector_msvc_helper(int);
template <class T1, class T2> using comp_ne_detector = decltype(comp_ne_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_lt_detector_msvc_helper(long) -> decltype(std::declval<S>() < std::declval<T>());
template <class S, class T> success comp_lt_detector_msvc_helper(int);
template <class T1, class T2> using comp_lt_detector = decltype(comp_lt_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> can_not_apply comp_lt_detector_msvc_helper(int);
template <class T1, class T2> using comp_lt_detector = decltype(comp_lt_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_le_detector_msvc_helper(long) -> decltype(std::declval<S>() <= std::declval<T>());
template <class S, class T> success comp_le_detector_msvc_helper(int);
template <class T1, class T2> using comp_le_detector = decltype(comp_le_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> can_not_apply comp_le_detector_msvc_helper(int);
template <class T1, class T2> using comp_le_detector = decltype(comp_le_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_gt_detector_msvc_helper(long) -> decltype(std::declval<S>() > std::declval<T>());
template <class S, class T> success comp_gt_detector_msvc_helper(int);
template <class T1, class T2> using comp_gt_detector = decltype(comp_gt_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> can_not_apply comp_gt_detector_msvc_helper(int);
template <class T1, class T2> using comp_gt_detector = decltype(comp_gt_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto comp_ge_detector_msvc_helper(long) -> decltype(std::declval<S>() >= std::declval<T>());
template <class S, class T> success comp_ge_detector_msvc_helper(int);
template <class T1, class T2> using comp_ge_detector = decltype(comp_ge_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> can_not_apply comp_ge_detector_msvc_helper(int);
template <class T1, class T2> using comp_ge_detector = decltype(comp_ge_detector_msvc_helper<T1,T2>(1L));
template <class S> auto hash_detector_msvc_helper(long) -> decltype(std::hash<S>{}(std::declval<S>()));
template <class S> can_not_apply hash_detector_msvc_helper(int);
template <class T1, class T2> using hash_detector = decltype(hash_detector_msvc_helper<T1,T2>(1L));
template <class S, class T> auto ostreamable_detector_msvc_helper(long) -> decltype(std::declval<S>() << std::declval<T>());
template <class S, class T> success ostreamable_detector_msvc_helper(int);
template <class S, class T> can_not_apply ostreamable_detector_msvc_helper(int);
template <class S, class T> using ostreamable_detector = decltype(ostreamable_detector_msvc_helper<S,T>(1L));
template <class S, class T> auto istreamable_detector_msvc_helper(long) -> decltype(std::declval<S>() >> std::declval<T>());
template <class S, class T> success istreamable_detector_msvc_helper(int);
template <class S, class T> can_not_apply istreamable_detector_msvc_helper(int);
template <class S, class T> using istreamable_detector = decltype(istreamable_detector_msvc_helper<S,T>(1L));
}}} // namespace boost::pfr::detail

View File

@@ -29,7 +29,11 @@ namespace boost { namespace pfr { namespace detail {
///////////////////// Structure that can be converted to reference to anything
struct ubiq_lref_constructor {
std::size_t ignore;
template <class Type> constexpr operator Type&() const noexcept { // Allows initialization of reference fields (T& and const T&)
template <class Type> constexpr operator Type&() const && noexcept { // tweak for template_unconstrained.cpp like cases
return detail::unsafe_declval<Type&>();
};
template <class Type> constexpr operator Type&() const & noexcept { // tweak for optional_chrono.cpp like cases
return detail::unsafe_declval<Type&>();
};
};
@@ -37,7 +41,7 @@ struct ubiq_lref_constructor {
///////////////////// Structure that can be converted to rvalue reference to anything
struct ubiq_rref_constructor {
std::size_t ignore;
template <class Type> /*constexpr*/ operator Type&&() const noexcept { // Allows initialization of rvalue reference fields and move-only types
template <class Type> /*constexpr*/ operator Type&&() const && noexcept { // Allows initialization of rvalue reference fields and move-only types
return detail::unsafe_declval<Type&&>();
};
};
@@ -196,7 +200,7 @@ constexpr std::size_t detect_fields_count_dispatch(size_t_<N>, int, int) noexcep
return detail::detect_fields_count_greedy<T, 0, N>(detail::multi_element_range{});
}
///////////////////// Returns non-flattened fields count
///////////////////// Returns fields count
template <class T>
constexpr std::size_t fields_count() noexcept {
using type = std::remove_cv_t<T>;
@@ -221,7 +225,7 @@ constexpr std::size_t fields_count() noexcept {
#ifdef __cpp_lib_is_aggregate
static_assert(
std::is_aggregate<type>::value // Does not return `true` for build in types.
std::is_aggregate<type>::value // Does not return `true` for built-in types.
|| std::is_scalar<type>::value,
"====================> Boost.PFR: Type must be aggregate initializable."
);

View File

@@ -1,41 +0,0 @@
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_FLAT_TIE_FROM_STRUCTURE_TUPLE_HPP
#define BOOST_PFR_DETAIL_FLAT_TIE_FROM_STRUCTURE_TUPLE_HPP
#pragma once
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
namespace boost { namespace pfr { namespace detail {
/// \brief A `std::tuple` capable of de-structuring assignment used to support
/// a tie of multiple lvalue references to \flattening{flattened} fields of an
/// aggregate T.
///
/// \sa boost::pfr::flat_tie_from_structure
///
template <typename... Elements>
struct flat_tie_from_structure_tuple : std::tuple<Elements&...> {
using base = std::tuple<Elements&...>;
using base::base;
template <typename T>
constexpr flat_tie_from_structure_tuple& operator= (T const& t) {
base::operator=(
detail::make_stdtiedtuple_from_tietuple(
detail::tie_as_flat_tuple(t),
detail::make_index_sequence<flat_tuple_size_v<T>>()));
return *this;
}
};
}}} // boost::pfr::detail
#endif // BOOST_PFR_DETAIL_FLAT_TIE_FROM_STRUCTURE_TUPLE_HPP

View File

@@ -121,12 +121,24 @@ namespace boost { namespace pfr { namespace detail {
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
template <typename T>
auto compute_hash(const T& value, long /*priority*/)
-> decltype(std::hash<T>()(value))
{
return std::hash<T>()(value);
}
template <typename T>
std::size_t compute_hash(const T& /*value*/, int /*priority*/) {
static_assert(sizeof(T) && false, "====================> Boost.PFR: std::hash not specialized for type T");
return 0;
}
template <std::size_t I, std::size_t N>
struct hash_impl {
template <class T>
constexpr static std::size_t compute(const T& val) noexcept {
typedef std::decay_t<typename detail::sequence_tuple::tuple_element<I, T>::type> elem_t;
std::size_t h = std::hash<elem_t>()( ::boost::pfr::detail::sequence_tuple::get<I>(val) );
std::size_t h = detail::compute_hash( ::boost::pfr::detail::sequence_tuple::get<I>(val), 1L );
detail::hash_combine(h, hash_impl<I + 1, N>::compute(val) );
return h;
}
@@ -145,6 +157,35 @@ namespace boost { namespace pfr { namespace detail {
return x < y ? x : y;
}
template <template <std::size_t, std::size_t> class Visitor, class T, class U>
constexpr bool binary_visit(const T& x, const U& y) {
constexpr std::size_t fields_count_lhs = detail::fields_count<std::remove_reference_t<T>>();
constexpr std::size_t fields_count_rhs = detail::fields_count<std::remove_reference_t<U>>();
constexpr std::size_t fields_count_min = detail::min_size(fields_count_lhs, fields_count_rhs);
typedef Visitor<0, fields_count_min> visitor_t;
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
return visitor_t::cmp(detail::tie_as_tuple(x), detail::tie_as_tuple(y));
#else
bool result = true;
::boost::pfr::detail::for_each_field_dispatcher(
x,
[&result, &y](const auto& lhs) {
::boost::pfr::detail::for_each_field_dispatcher(
y,
[&result, &lhs](const auto& rhs) {
result = visitor_t::cmp(lhs, rhs);
},
detail::make_index_sequence<fields_count_rhs>{}
);
},
detail::make_index_sequence<fields_count_lhs>{}
);
return result;
#endif
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_FUNCTIONAL_HPP

View File

@@ -46,7 +46,7 @@ struct join_sequences<std::integer_sequence<T, A...>, std::integer_sequence<T, B
template <typename T, T Min, T Max>
struct build_sequence_impl {
static_assert(Min < Max, "Start of range must be less than it's end");
static_assert(Min < Max, "Start of range must be less than its end");
static constexpr T size = Max - Min;
using type = typename join_sequences<
typename build_sequence_impl<T, Min, Min + size / 2>::type,

View File

@@ -14,13 +14,11 @@
#include <utility>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/rvalue_t.hpp>
#include <boost/pfr/detail/size_t_.hpp>
namespace boost { namespace pfr { namespace detail {
template <std::size_t Index>
using size_t_ = std::integral_constant<std::size_t, Index >;
// Our own implementation of std::aligned_storage. On godbolt with MSVC, I have compilation errors
// using the standard version, it seems the compiler cannot generate default ctor.
@@ -69,7 +67,7 @@ template <typename U, typename S>
class offset_based_getter {
using this_t = offset_based_getter<U, S>;
static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type!");
static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type! Maybe the user-provided type is not a SimpleAggregate?");
static_assert(alignof(U) == alignof(S), "====================> Boost.PFR: Member sequence does not indicate correct alignment for struct type!");
static_assert(!std::is_const<U>::value, "====================> Boost.PFR: const should be stripped from user-defined type when using offset_based_getter or overload resolution will be ambiguous later, this indicates an error within pfr");

View File

@@ -13,7 +13,7 @@
#include <utility> // metaprogramming stuff
#include <cstddef> // std::size_t
///////////////////// Tuple that holds it's values in the supplied order
///////////////////// Tuple that holds its values in the supplied order
namespace boost { namespace pfr { namespace detail { namespace sequence_tuple {
template <std::size_t N, class T>

View File

@@ -30,6 +30,17 @@ constexpr auto make_stdtiedtuple_from_tietuple(const T& t, std::index_sequence<I
);
}
template <class T, std::size_t... I>
constexpr auto make_conststdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
return std::tuple<
std::add_lvalue_reference_t<std::add_const_t<
std::remove_reference_t<decltype(boost::pfr::detail::sequence_tuple::get<I>(t))>
>>...
>(
boost::pfr::detail::sequence_tuple::get<I>(t)...
);
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_STDTUPLE_HPP

View File

@@ -8,14 +8,13 @@
#define BOOST_PFR_DETAIL_TIE_FROM_STRUCTURE_TUPLE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/core.hpp>
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/tuple_size.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
#include <tuple>

View File

@@ -18,7 +18,7 @@ void report_if_you_see_link_error_with_this_function() noexcept;
// For returning non default constructible types. Do NOT use at runtime!
//
// GCC's std::declval may not be used in potentionally evaluated contexts,
// GCCs std::declval may not be used in potentionally evaluated contexts,
// so we reinvent it.
template <class T>
constexpr T unsafe_declval() noexcept {

View File

@@ -1,19 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_HPP
#define BOOST_PFR_FLAT_HPP
/// \file boost/pfr/flat.hpp
/// Includes all the Boost.PFR headers that define `flat_*` functions, except \xmlonly<link linkend='header.boost.pfr.flat.global_ops_hpp'>boost/pfr/flat/global_ops.hpp</link>\endxmlonly
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/ops.hpp>
#include <boost/pfr/flat/io.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/flat/functions_for.hpp>
#endif // BOOST_PFR_FLAT_HPP

View File

@@ -1,161 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_CORE_HPP
#define BOOST_PFR_FLAT_CORE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/detail/for_each_field_impl.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/detail/flat_tie_from_structure_tuple.hpp>
namespace boost { namespace pfr {
/// \brief Returns reference or const reference to a field with index `I` in \flattening{flattened} T.
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s {10, 11};
/// assert(boost::pfr::flat_get<0>(s) == 10);
/// boost::pfr::flat_get<1>(s) = 0;
/// \endcode
template <std::size_t I, class T>
decltype(auto) flat_get(const T& val) noexcept {
return boost::pfr::detail::sequence_tuple::get<I>( boost::pfr::detail::tie_as_flat_tuple(val) );
}
/// \overload flat_get
template <std::size_t I, class T>
decltype(auto) flat_get(T& val /* @cond */, std::enable_if_t< std::is_trivially_assignable<T, T>::value>* = 0/* @endcond */ ) noexcept {
return boost::pfr::detail::sequence_tuple::get<I>( boost::pfr::detail::tie_as_flat_tuple(val) );
}
/// \brief `flat_tuple_element` has a `typedef type-of-the-field-with-index-I-in-\flattening{flattened}-T type;`
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::flat_tuple_element<0, my_structure>::type > v;
/// \endcode
template <std::size_t I, class T>
using flat_tuple_element = std::remove_reference<
typename boost::pfr::detail::sequence_tuple::tuple_element<I, decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>())) >::type
>;
/// \brief Type of a field with index `I` in \flattening{flattened} `T`
///
/// \b Example:
/// \code
/// std::vector< boost::pfr::flat_tuple_element_t<0, my_structure> > v;
/// \endcode
template <std::size_t I, class T>
using flat_tuple_element_t = typename flat_tuple_element<I, T>::type;
/// \brief Creates an `std::tuple` from a \flattening{flattened} T.
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s {10, 11};
/// std::tuple<int, short> t = flat_make_tuple(s);
/// assert(flat_get<0>(t) == 10);
/// \endcode
template <class T>
auto flat_structure_to_tuple(const T& val) noexcept {
return detail::make_stdtuple_from_tietuple(
detail::tie_as_flat_tuple(val),
detail::make_index_sequence< flat_tuple_size_v<T> >()
);
}
/// \brief Creates an `std::tuple` with lvalue references to fields of a \flattening{flattened} T.
///
/// \rcast
///
/// \b Requires: `T` must not have const fields.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// flat_structure_tie(s) = std::tuple<int, short>{10, 11};
/// assert(s.s == 11);
/// \endcode
template <class T>
auto flat_structure_tie(T& val /* @cond */, std::enable_if_t< std::is_trivially_assignable<T, T>::value>* = 0 /* @endcond */) noexcept {
return detail::make_stdtiedtuple_from_tietuple(
detail::tie_as_flat_tuple(val),
detail::make_index_sequence< flat_tuple_size_v<T> >()
);
}
/// Calls `func` for each field of a \flattening{flattened} POD `value`.
///
/// \rcast
///
/// \param func must have one of the following signatures:
/// * any_return_type func(U&& field) // field of value is perfect forwarded to function
/// * any_return_type func(U&& field, std::size_t i)
/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \param value After \flattening{flattening} to each field of this variable will be the `func` applied.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// int sum = 0;
/// for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
/// assert(sum == 42);
/// \endcode
template <class T, class F>
void flat_for_each_field(T&& value, F&& func) {
auto tup = detail::tie_as_flat_tuple(value);
::boost::pfr::detail::for_each_field_impl(
tup,
std::forward<F>(func),
detail::make_index_sequence< flat_tuple_size_v<T> >{},
std::is_rvalue_reference<T&&>{}
);
}
/// \brief Create a tuple of lvalue references capable of de-structuring
/// assignment from \flattening{flattened} fields of an aggregate T.
///
/// \b Example:
/// \code
/// auto f() {
/// struct { struct { int x, y } p; short s; } res { { 4, 5 }, 6 };
/// return res;
/// }
/// auto [x, y, s] = flat_structure_tie(f());
/// flat_tie_from_structure(x, y, s) = f();
/// \endcode
template <typename... Elements>
constexpr detail::flat_tie_from_structure_tuple<Elements...> flat_tie_from_structure(Elements&... args) noexcept {
return detail::flat_tie_from_structure_tuple<Elements...>(args...);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_CORE_HPP

View File

@@ -1,81 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP
#define BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/io.hpp>
/// \def BOOST_PFR_FLAT_FUNCTIONS_FOR(T)
/// Defines comparison operators and stream operators for T.
/// If POD is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/flat/functions_for.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// BOOST_PFR_FLAT_FUNCTIONS_FOR(comparable_struct)
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \rcast
///
/// \podops for other ways to define operators and more details.
///
/// \b Defines \b following \b for \b T:
/// \code
/// bool operator==(const T& lhs, const T& rhs) noexcept;
/// bool operator!=(const T& lhs, const T& rhs) noexcept;
/// bool operator< (const T& lhs, const T& rhs) noexcept;
/// bool operator> (const T& lhs, const T& rhs) noexcept;
/// bool operator<=(const T& lhs, const T& rhs) noexcept;
/// bool operator>=(const T& lhs, const T& rhs) noexcept;
///
/// template <class Char, class Traits>
/// std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
///
/// template <class Char, class Traits>
/// std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
///
/// // helper function for Boost unordered containers and boost::hash<>.
/// std::size_t hash_value(const T& value) noexcept;
/// \endcode
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::flat_write(out, value); \
return out; \
} \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::flat_read(in, value); \
return in; \
} \
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) noexcept { \
return ::boost::pfr::flat_hash<T>{}(v); \
} \
/**/
#endif // BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP

View File

@@ -1,233 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_FUNCTORS_HPP
#define BOOST_PFR_FLAT_FUNCTORS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/functional.hpp>
#include <boost/pfr/flat/core.hpp>
/// \file boost/pfr/functors.hpp
/// Contains functors that can work with PODs and are close to the Standard Library ones.
/// Each functor \flattening{flattens} the POD type and iterates over its fields.
///
/// \rcast
namespace boost { namespace pfr {
///////////////////// Comparisons
/// \brief std::equal_to like flattening comparator
template <class T = void> struct flat_equal_to {
/// \return \b true if each field of \b x equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_equal_to<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::equal_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
};
/// @endcond
/// \brief std::not_equal like flattening comparator
template <class T = void> struct flat_not_equal {
/// \return \b true if at least one field \b x not equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_not_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater like flattening comparator
template <class T = void> struct flat_greater {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::greater_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_greater<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::greater_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less like flattening comparator
template <class T = void> struct flat_less {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::less_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_less<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::less_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater_equal like flattening comparator
template <class T = void> struct flat_greater_equal {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::greater_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_greater_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::greater_equal_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less_equal like flattening comparator
template <class T = void> struct flat_less_equal {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
///
/// \rcast
bool operator()(const T& x, const T& y) const noexcept {
return detail::less_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
/// This typedef exists only if T \b is void
typedef std::true_type is_transparent;
/// This operator allows comparison of \b x and \b y that have different type.
/// \pre Exists only if T \b is void.
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
#endif
};
/// @cond
template <> struct flat_less_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const noexcept {
return detail::less_equal_impl<
0,
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::hash like flattening functor
template <class T> struct flat_hash {
/// \return hash value of \b x.
///
/// \rcast
std::size_t operator()(const T& x) const noexcept {
return detail::hash_impl<0, flat_tuple_size_v<T> >::compute(detail::tie_as_flat_tuple(x));
}
};
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_FUNCTORS_HPP

View File

@@ -1,125 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_GLOBAL_OPS_HPP
#define BOOST_PFR_FLAT_GLOBAL_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/flat/io.hpp>
/// \file boost/pfr/flat/global_ops.hpp
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.
/// If POD is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/flat/global_ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \rcast
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b defines:
/// @cond
namespace boost { namespace pfr { namespace detail {
template <class T, class U>
using enable_flat_comparisons = std::enable_if_t<
std::is_same<T, U>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
bool
>;
}}} // namespace boost::pfr::detail
/// @endcond
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost unordered containers and boost::hash<>.
template <class T> std::size_t hash_value(const T& value) noexcept;
#else
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator==(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator!=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator<(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_less<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator>(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_greater<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator<=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_flat_comparisons<T, U> operator>=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_ostream<Char, Traits>&
> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
::boost::pfr::flat_write(out, value);
return out;
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_istream<Char, Traits>&
> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
::boost::pfr::flat_read(in, value);
return in;
}
template <class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::size_t
> hash_value(const T& value) noexcept {
return ::boost::pfr::flat_hash<T>{}(value);
}
#endif
#endif // BOOST_PFR_FLAT_GLOBAL_OPS_HPP

View File

@@ -1,75 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_IO_HPP
#define BOOST_PFR_FLAT_IO_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
namespace boost { namespace pfr {
/// \brief Writes \flattening{flattened} POD `value` to `out`
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// flat_write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void flat_write(std::basic_ostream<Char, Traits>& out, const T& value) {
out << '{';
detail::print_impl<0, flat_tuple_size_v<T> >::print(out, detail::tie_as_flat_tuple(value));
out << '}';
}
/// Reads \flattening{flattened} POD `value` from stream `in`
///
/// \rcast
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
template <class Char, class Traits, class T>
void flat_read(std::basic_istream<Char, Traits>& in, T& value) {
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
auto tuple = detail::tie_as_flat_tuple(value);
detail::read_impl<0, flat_tuple_size_v<T> >::read(in, tuple);
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_IO_HPP

View File

@@ -1,151 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_OPS_HPP
#define BOOST_PFR_FLAT_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/io.hpp>
/// \file boost/pfr/flat/ops.hpp
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.
/// If POD is comparable or streamable using it's own operator or it's conversion operator, then the original operator is used.
///
/// Just write \b using \b namespace \b flat_ops; and operators will be available in scope.
///
/// \b Example:
/// \code
/// #include <boost/pfr/flat/ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// using namespace flat_ops;
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \rcast
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b contains:
namespace boost { namespace pfr {
namespace detail {
///////////////////// Helper typedef that it used by all the enable_flat_not_*_comp_t
template <template <class, class> class Detector, class T>
using enable_flat_not_comp_base_t = typename std::enable_if<
not_appliable<Detector, T const&, T const&>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
bool
>::type;
///////////////////// std::enable_if_t like functions that enable only if types do not support operation and are PODs
template <class T> using enable_flat_not_eq_comp_t = enable_flat_not_comp_base_t<comp_eq_detector, T>;
template <class T> using enable_flat_not_ne_comp_t = enable_flat_not_comp_base_t<comp_ne_detector, T>;
template <class T> using enable_flat_not_lt_comp_t = enable_flat_not_comp_base_t<comp_lt_detector, T>;
template <class T> using enable_flat_not_le_comp_t = enable_flat_not_comp_base_t<comp_le_detector, T>;
template <class T> using enable_flat_not_gt_comp_t = enable_flat_not_comp_base_t<comp_gt_detector, T>;
template <class T> using enable_flat_not_ge_comp_t = enable_flat_not_comp_base_t<comp_ge_detector, T>;
template <class Stream, class Type>
using enable_flat_not_ostreamable_t = typename std::enable_if<
not_appliable<ostreamable_detector, Stream&, Type const&>::value && std::is_trivial<Type>::value
&& std::is_standard_layout<Type>::value,
Stream&
>::type;
template <class Stream, class Type>
using enable_flat_not_istreamable_t = typename std::enable_if<
not_appliable<istreamable_detector, Stream&, Type&>::value && std::is_trivial<Type>::value
&& std::is_standard_layout<Type>::value,
Stream&
>::type;
} // namespace detail
namespace flat_ops {
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost
template <class T> std::size_t hash_value(const T& value) noexcept;
#else
template <class T>
static detail::enable_flat_not_eq_comp_t<T> operator==(const T& lhs, const T& rhs) noexcept {
return flat_equal_to<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_ne_comp_t<T> operator!=(const T& lhs, const T& rhs) noexcept {
return flat_not_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_lt_comp_t<T> operator<(const T& lhs, const T& rhs) noexcept {
return flat_less<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_gt_comp_t<T> operator>(const T& lhs, const T& rhs) noexcept {
return flat_greater<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_le_comp_t<T> operator<=(const T& lhs, const T& rhs) noexcept {
return flat_less_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_flat_not_ge_comp_t<T> operator>=(const T& lhs, const T& rhs) noexcept {
return flat_greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static detail::enable_flat_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
boost::pfr::flat_write(out, value);
return out;
}
template <class Char, class Traits, class T>
static detail::enable_flat_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
boost::pfr::flat_read(in, value);
return in;
}
template <class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::size_t
> hash_value(const T& value) noexcept {
return flat_hash<T>{}(value);
}
#endif
} // namespace flat_ops
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_OPS_HPP

View File

@@ -1,40 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_TUPLE_SIZE_HPP
#define BOOST_PFR_FLAT_TUPLE_SIZE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/core14.hpp>
namespace boost { namespace pfr {
/// Has a static const member variable `value` that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size<my_structure>::value > a;
/// \endcode
template <class T>
using flat_tuple_size = boost::pfr::detail::size_t_<decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>()))::size_v>;
/// `flat_tuple_size_v` is a template variable that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size_v<my_structure> > a;
/// \endcode
template <class T>
constexpr std::size_t flat_tuple_size_v = flat_tuple_size<T>::value;
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_TUPLE_SIZE_HPP

View File

@@ -3,26 +3,43 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
#ifndef BOOST_PFR_FUNCTIONS_FOR_HPP
#define BOOST_PFR_FUNCTIONS_FOR_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/io.hpp>
#include <boost/pfr/ops_fields.hpp>
#include <boost/pfr/io_fields.hpp>
/// \def BOOST_PFR_PRECISE_FUNCTIONS_FOR(T)
/// Defines comparison operators and stream operators for T.
/// If type T is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
/// \file boost/pfr/functions_for.hpp
/// Contains BOOST_PFR_FUNCTIONS_FOR macro that defined comparison and stream operators for T along with hash_value function.
/// \b Example:
/// \code
/// #include <boost/pfr/functions_for.hpp>
///
/// namespace my_namespace {
/// struct my_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// BOOST_PFR_FUNCTIONS_FOR(my_struct)
/// }
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b Synopsis:
/// \def BOOST_PFR_FUNCTIONS_FOR(T)
/// Defines comparison and stream operators for T along with hash_value function.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/functions_for.hpp>
/// #include <boost/pfr/functions_for.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// BOOST_PFR_PRECISE_FUNCTIONS_FOR(comparable_struct)
/// BOOST_PFR_FUNCTIONS_FOR(comparable_struct)
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
@@ -52,28 +69,25 @@
/// std::size_t hash_value(const T& value);
/// \endcode
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::write(out, value); \
return out; \
} \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::read(in, value); \
return in; \
} \
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) { \
return ::boost::pfr::hash<T>{}(v); \
} \
#define BOOST_PFR_FUNCTIONS_FOR(T) \
BOOST_PFR_MAYBE_UNUSED inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::eq_fields(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::ne_fields(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::lt_fields(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::gt_fields(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::le_fields(lhs, rhs); } \
BOOST_PFR_MAYBE_UNUSED inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::ge_fields(lhs, rhs); } \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED inline ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
return out << ::boost::pfr::io_fields(value); \
} \
template <class Char, class Traits> \
BOOST_PFR_MAYBE_UNUSED inline ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
return in >> ::boost::pfr::io_fields(value); \
} \
BOOST_PFR_MAYBE_UNUSED inline std::size_t hash_value(const T& v) { \
return ::boost::pfr::hash_fields(v); \
} \
/**/
#endif // BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
#endif // BOOST_PFR_FUNCTIONS_FOR_HPP

View File

@@ -3,67 +3,45 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_FUNCTORS_HPP
#define BOOST_PFR_PRECISE_FUNCTORS_HPP
#ifndef BOOST_PFR_FUNCTORS_HPP
#define BOOST_PFR_FUNCTORS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/ops.hpp>
#include <boost/pfr/detail/functional.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
/// \file boost/pfr/functors.hpp
/// Contains functors that are close to the Standard Library ones.
/// Each functor iterates over fields of the type.
/// Each functor calls corresponding Boost.PFR function from boost/pfr/ops.hpp
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
/// \b Example:
/// \code
/// #include <boost/pfr/functors.hpp>
/// struct my_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// std::unordered_set<
/// my_struct,
/// boost::pfr::hash<>,
/// boost::pfr::equal_to<>
/// > my_set;
/// \endcode
///
/// \b Synopsis:
namespace boost { namespace pfr {
namespace detail {
template <template <std::size_t, std::size_t> class Visitor, class T, class U>
bool binary_visit(const T& x, const U& y) {
constexpr std::size_t fields_count_lhs = detail::fields_count<std::remove_reference_t<T>>();
constexpr std::size_t fields_count_rhs = detail::fields_count<std::remove_reference_t<U>>();
constexpr std::size_t fields_count_min = detail::min_size(fields_count_lhs, fields_count_rhs);
typedef Visitor<0, fields_count_min> visitor_t;
#if BOOST_PFR_USE_CPP17
return visitor_t::cmp(detail::tie_as_tuple(x), detail::tie_as_tuple(y));
#else
bool result = true;
::boost::pfr::detail::for_each_field_dispatcher(
x,
[&result, &y](const auto& lhs) {
::boost::pfr::detail::for_each_field_dispatcher(
y,
[&result, &lhs](const auto& rhs) {
result = visitor_t::cmp(lhs, rhs);
},
detail::make_index_sequence<fields_count_rhs>{}
);
},
detail::make_index_sequence<fields_count_lhs>{}
);
return result;
#endif
}
} // namespace detail
///////////////////// Comparisons
/// \brief std::equal_to like comparator
/// \brief std::equal_to like comparator that returns \forcedlink{eq}(x, y)
template <class T = void> struct equal_to {
/// \return \b true if each field of \b x equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::equal_impl>(x, y);
return boost::pfr::eq(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
@@ -80,17 +58,18 @@ template <class T = void> struct equal_to {
template <> struct equal_to<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::equal_impl>(x, y);
return boost::pfr::eq(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::not_equal like comparator
/// \brief std::not_equal like comparator that returns \forcedlink{ne}(x, y)
template <class T = void> struct not_equal {
/// \return \b true if at least one field \b x not equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::not_equal_impl>(x, y);
return boost::pfr::ne(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
@@ -107,18 +86,18 @@ template <class T = void> struct not_equal {
template <> struct not_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::not_equal_impl>(x, y);
return boost::pfr::ne(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater like comparator
/// \brief std::greater like comparator that returns \forcedlink{gt}(x, y)
template <class T = void> struct greater {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::greater_impl>(x, y);
return boost::pfr::gt(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
@@ -135,18 +114,18 @@ template <class T = void> struct greater {
template <> struct greater<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::greater_impl>(x, y);
return boost::pfr::gt(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less like comparator
/// \brief std::less like comparator that returns \forcedlink{lt}(x, y)
template <class T = void> struct less {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::less_impl>(x, y);
return boost::pfr::lt(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
@@ -163,19 +142,19 @@ template <class T = void> struct less {
template <> struct less<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::less_impl>(x, y);
return boost::pfr::lt(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::greater_equal like comparator
/// \brief std::greater_equal like comparator that returns \forcedlink{ge}(x, y)
template <class T = void> struct greater_equal {
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::greater_equal_impl>(x, y);
return boost::pfr::ge(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
@@ -192,19 +171,19 @@ template <class T = void> struct greater_equal {
template <> struct greater_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::greater_equal_impl>(x, y);
return boost::pfr::ge(x, y);
}
typedef std::true_type is_transparent;
};
/// @endcond
/// \brief std::less_equal like comparator
/// \brief std::less_equal like comparator that returns \forcedlink{le}(x, y)
template <class T = void> struct less_equal {
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y;
/// or if each field of \b x equals the field with same index of \b y.
bool operator()(const T& x, const T& y) const {
return detail::binary_visit<detail::less_equal_impl>(x, y);
return boost::pfr::le(x, y);
}
#ifdef BOOST_PFR_DOXYGEN_INVOKED
@@ -221,7 +200,7 @@ template <class T = void> struct less_equal {
template <> struct less_equal<void> {
template <class T, class U>
bool operator()(const T& x, const U& y) const {
return detail::binary_visit<detail::less_equal_impl>(x, y);
return boost::pfr::le(x, y);
}
typedef std::true_type is_transparent;
@@ -229,31 +208,14 @@ template <> struct less_equal<void> {
/// @endcond
/// \brief std::hash like functor
/// \brief std::hash like functor that returns \forcedlink{hash_value}(x)
template <class T> struct hash {
/// \return hash value of \b x.
std::size_t operator()(const T& x) const {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
#if BOOST_PFR_USE_CPP17
return detail::hash_impl<0, fields_count_val>::compute(detail::tie_as_tuple(x));
#else
std::size_t result = 0;
::boost::pfr::detail::for_each_field_dispatcher(
x,
[&result](const auto& lhs) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
result = detail::hash_impl<0, fields_count_val_lambda>::compute(lhs);
},
detail::make_index_sequence<fields_count_val>{}
);
return result;
#endif
return boost::pfr::hash_value(x);
}
};
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_FUNCTORS_HPP
#endif // BOOST_PFR_FUNCTORS_HPP

113
include/boost/pfr/io.hpp Normal file
View File

@@ -0,0 +1,113 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_IO_HPP
#define BOOST_PFR_IO_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/io_fields.hpp>
/// \file boost/pfr/io.hpp
/// Contains IO stream manipulator \forcedlink{io} for types.
/// If type is streamable using its own operator or its conversion operator, then the types operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/io.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// std::cout << boost::pfr::io(s1); // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b Synopsis:
namespace boost { namespace pfr {
namespace detail {
///////////////////// Helper typedefs
template <class Stream, class Type>
using enable_not_ostreamable_t = std::enable_if_t<
not_appliable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
Stream&
>;
template <class Stream, class Type>
using enable_not_istreamable_t = std::enable_if_t<
not_appliable<istreamable_detector, Stream&, Type&>::value,
Stream&
>;
template <class Stream, class Type>
using enable_ostreamable_t = std::enable_if_t<
!not_appliable<ostreamable_detector, Stream&, const std::remove_reference_t<Type>&>::value,
Stream&
>;
template <class Stream, class Type>
using enable_istreamable_t = std::enable_if_t<
!not_appliable<istreamable_detector, Stream&, Type&>::value,
Stream&
>;
///////////////////// IO impl
template <class T>
struct io_impl {
T value;
};
template <class Char, class Traits, class T>
enable_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, io_impl<T>&& x) {
return out << boost::pfr::io_fields(std::forward<T>(x.value));
}
template <class Char, class Traits, class T>
enable_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, io_impl<T>&& x) {
return out << x.value;
}
template <class Char, class Traits, class T>
enable_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, io_impl<T>&& x) {
return in >> boost::pfr::io_fields(std::forward<T>(x.value));
}
template <class Char, class Traits, class T>
enable_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, io_impl<T>&& x) {
return in >> x.value;
}
} // namespace detail
/// IO manupulator to read/write \aggregate `value` using its IO stream operators or using \forcedlink{io_fields} if operators are not awailable.
///
/// \b Example:
/// \code
/// struct my_struct { int i; short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> boost::pfr::io(s);
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
///
/// \customio
template <class T>
auto io(T&& value) noexcept {
return detail::io_impl<T>{std::forward<T>(value)};
}
}} // namespace boost::pfr
#endif // BOOST_PFR_IO_HPP

View File

@@ -0,0 +1,164 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_IO_FIELDS_HPP
#define BOOST_PFR_IO_FIELDS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/core.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/tuple_size.hpp>
/// \file boost/pfr/io_fields.hpp
/// Contains IO manupulator \forcedlink{io_fields} to read/write \aggregate `value` field-by-field.
///
/// \b Example:
/// \code
/// struct my_struct {
/// int i;
/// short s;
/// };
///
/// std::ostream& operator<<(std::ostream& os, const my_struct& x) {
/// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }"
/// }
///
/// std::istream& operator>>(std::istream& is, my_struct& x) {
/// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }"
/// }
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b Synopsis:
namespace boost { namespace pfr {
namespace detail {
template <class T>
struct io_fields_impl {
T value;
};
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, io_fields_impl<const T&>&& x) {
const T& value = x.value;
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
out << '{';
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
detail::print_impl<0, fields_count_val>::print(out, detail::tie_as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&out](const auto& val) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
detail::print_impl<0, fields_count_val_lambda>::print(out, val);
},
detail::make_index_sequence<fields_count_val>{}
);
#endif
return out << '}';
}
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, io_fields_impl<T>&& x) {
return out << io_fields_impl<const std::remove_reference_t<T>&>{x.value};
}
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T&>&& x) {
T& value = x.value;
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
detail::read_impl<0, fields_count_val>::read(in, detail::tie_as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&in](const auto& val) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
detail::read_impl<0, fields_count_val_lambda>::read(in, val);
},
detail::make_index_sequence<fields_count_val>{}
);
#endif
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
return in;
}
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<const T&>&& ) {
static_assert(sizeof(T) && false, "====================> Boost.PFR: Atetmpt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier.");
return in;
}
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, io_fields_impl<T>&& ) {
static_assert(sizeof(T) && false, "====================> Boost.PFR: Atetmpt to use istream operator on a boost::pfr::io_fields wrapped temporary of type T.");
return in;
}
} // namespace detail
/// IO manupulator to read/write \aggregate `value` field-by-field.
///
/// \b Example:
/// \code
/// struct my_struct {
/// int i;
/// short s;
/// };
///
/// std::ostream& operator<<(std::ostream& os, const my_struct& x) {
/// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }"
/// }
///
/// std::istream& operator>>(std::istream& is, my_struct& x) {
/// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }"
/// }
/// \endcode
///
/// Input and output streaming operators for `boost::pfr::io_fields` are symmetric, meaning that you get the original value by streaming it and
/// reading back if each fields streaming operator is symmetric.
///
/// \customio
template <class T>
auto io_fields(T&& value) noexcept {
return detail::io_fields_impl<T>{std::forward<T>(value)};
}
}} // namespace boost::pfr
#endif // BOOST_PFR_IO_FIELDS_HPP

187
include/boost/pfr/ops.hpp Normal file
View File

@@ -0,0 +1,187 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_OPS_HPP
#define BOOST_PFR_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/ops_fields.hpp>
/// \file boost/pfr/ops.hpp
/// Contains comparison and hashing functions.
/// If type is comparable using its own operator or its conversion operator, then the types operator is used. Otherwise
/// the operation is done via corresponding function from boost/pfr/ops.hpp header.
///
/// \b Example:
/// \code
/// #include <boost/pfr/ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(boost::pfr::lt(s1, s2));
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b Synopsis:
namespace boost { namespace pfr {
namespace detail {
///////////////////// Helper typedefs that are used by all the ops
template <template <class, class> class Detector, class T, class U>
using enable_not_comp_base_t = std::enable_if_t<
not_appliable<Detector, T const&, U const&>::value,
bool
>;
template <template <class, class> class Detector, class T, class U>
using enable_comp_base_t = std::enable_if_t<
!not_appliable<Detector, T const&, U const&>::value,
bool
>;
///////////////////// std::enable_if_t like functions that enable only if types do not support operation
template <class T, class U> using enable_not_eq_comp_t = enable_not_comp_base_t<comp_eq_detector, T, U>;
template <class T, class U> using enable_not_ne_comp_t = enable_not_comp_base_t<comp_ne_detector, T, U>;
template <class T, class U> using enable_not_lt_comp_t = enable_not_comp_base_t<comp_lt_detector, T, U>;
template <class T, class U> using enable_not_le_comp_t = enable_not_comp_base_t<comp_le_detector, T, U>;
template <class T, class U> using enable_not_gt_comp_t = enable_not_comp_base_t<comp_gt_detector, T, U>;
template <class T, class U> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T, U>;
template <class T> using enable_not_hashable_t = std::enable_if_t<
not_appliable<hash_detector, const T&, const T&>::value,
std::size_t
>;
///////////////////// std::enable_if_t like functions that enable only if types do support operation
template <class T, class U> using enable_eq_comp_t = enable_comp_base_t<comp_eq_detector, T, U>;
template <class T, class U> using enable_ne_comp_t = enable_comp_base_t<comp_ne_detector, T, U>;
template <class T, class U> using enable_lt_comp_t = enable_comp_base_t<comp_lt_detector, T, U>;
template <class T, class U> using enable_le_comp_t = enable_comp_base_t<comp_le_detector, T, U>;
template <class T, class U> using enable_gt_comp_t = enable_comp_base_t<comp_gt_detector, T, U>;
template <class T, class U> using enable_ge_comp_t = enable_comp_base_t<comp_ge_detector, T, U>;
template <class T> using enable_hashable_t = std::enable_if_t<
!not_appliable<hash_detector, const T&, const T&>::value,
std::size_t
>;
} // namespace detail
/// \brief Compares lhs and rhs for equality using their own comparison and conversion operators; if no operators avalable returns \forcedlink{eq_fields}(lhs, rhs).
///
/// \returns true if lhs is equal to rhs; false otherwise
template <class T, class U>
constexpr detail::enable_not_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) noexcept {
return boost::pfr::eq_fields(lhs, rhs);
}
/// \overload eq
template <class T, class U>
constexpr detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
return lhs == rhs;
}
/// \brief Compares lhs and rhs for inequality using their own comparison and conversion operators; if no operators avalable returns \forcedlink{ne_fields}(lhs, rhs).
///
/// \returns true if lhs is not equal to rhs; false otherwise
template <class T, class U>
constexpr detail::enable_not_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) noexcept {
return boost::pfr::ne_fields(lhs, rhs);
}
/// \overload ne
template <class T, class U>
constexpr detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
return lhs != rhs;
}
/// \brief Compares lhs and rhs for less-than using their own comparison and conversion operators; if no operators avalable returns \forcedlink{lt_fields}(lhs, rhs).
///
/// \returns true if lhs is less than rhs; false otherwise
template <class T, class U>
constexpr detail::enable_not_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) noexcept {
return boost::pfr::lt_fields(lhs, rhs);
}
/// \overload lt
template <class T, class U>
constexpr detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
return lhs < rhs;
}
/// \brief Compares lhs and rhs for greater-than using their own comparison and conversion operators; if no operators avalable returns \forcedlink{lt_fields}(lhs, rhs).
///
/// \returns true if lhs is greater than rhs; false otherwise
template <class T, class U>
constexpr detail::enable_not_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) noexcept {
return boost::pfr::gt_fields(lhs, rhs);
}
/// \overload gt
template <class T, class U>
constexpr detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
return lhs > rhs;
}
/// \brief Compares lhs and rhs for less-equal using their own comparison and conversion operators; if no operators avalable returns \forcedlink{le_fields}(lhs, rhs).
///
/// \returns true if lhs is less or equal to rhs; false otherwise
template <class T, class U>
constexpr detail::enable_not_le_comp_t<T, U> le(const T& lhs, const U& rhs) noexcept {
return boost::pfr::le_fields(lhs, rhs);
}
/// \overload le
template <class T, class U>
constexpr detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
return lhs <= rhs;
}
/// \brief Compares lhs and rhs for greater-equal using their own comparison and conversion operators; if no operators avalable returns \forcedlink{ge_fields}(lhs, rhs).
///
/// \returns true if lhs is greater or equal to rhs; false otherwise
template <class T, class U>
constexpr detail::enable_not_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) noexcept {
return boost::pfr::ge_fields(lhs, rhs);
}
/// \overload ge
template <class T, class U>
constexpr detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
return lhs >= rhs;
}
/// \brief Hashes value using its own std::hash specialization; if no std::hash specialization avalable returns \forcedlink{hash_fields}(value).
///
/// \returns std::size_t with hash of the value
template <class T>
constexpr detail::enable_not_hashable_t<T> hash_value(const T& value) noexcept {
return boost::pfr::hash_fields(value);
}
/// \overload hash_value
template <class T>
constexpr detail::enable_hashable_t<T> hash_value(const T& value) {
return std::hash<T>{}(value);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_OPS_HPP

View File

@@ -0,0 +1,127 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_OPS_FIELDS_HPP
#define BOOST_PFR_OPS_FIELDS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/core.hpp>
#include <boost/pfr/detail/functional.hpp>
/// \file boost/pfr/ops_fields.hpp
/// Contains field-by-fields comparison and hash functions.
///
/// \b Example:
/// \code
/// #include <boost/pfr/ops_fields.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1};
/// comparable_struct s2 {0, 2};
/// assert(boost::pfr::lt_fields(s1, s2));
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b Synopsis:
namespace boost { namespace pfr {
/// Does a field-by-field equality comparison.
///
/// \returns `L == R && tuple_size_v<T> == tuple_size_v<U>`, where `L` and
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
template <class T, class U>
constexpr bool eq_fields(const T& lhs, const U& rhs) noexcept {
return detail::binary_visit<detail::equal_impl>(lhs, rhs);
}
/// Does a field-by-field inequality comparison.
///
/// \returns `L != R || tuple_size_v<T> != tuple_size_v<U>`, where `L` and
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
template <class T, class U>
constexpr bool ne_fields(const T& lhs, const U& rhs) noexcept {
return detail::binary_visit<detail::not_equal_impl>(lhs, rhs);
}
/// Does a field-by-field greter comparison.
///
/// \returns `L > R || (L == R && tuple_size_v<T> > tuple_size_v<U>)`, where `L` and
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
template <class T, class U>
constexpr bool gt_fields(const T& lhs, const U& rhs) noexcept {
return detail::binary_visit<detail::greater_impl>(lhs, rhs);
}
/// Does a field-by-field less comparison.
///
/// \returns `L < R || (L == R && tuple_size_v<T> < tuple_size_v<U>)`, where `L` and
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
template <class T, class U>
constexpr bool lt_fields(const T& lhs, const U& rhs) noexcept {
return detail::binary_visit<detail::less_impl>(lhs, rhs);
}
/// Does a field-by-field greater equal comparison.
///
/// \returns `L > R || (L == R && tuple_size_v<T> >= tuple_size_v<U>)`, where `L` and
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
template <class T, class U>
constexpr bool ge_fields(const T& lhs, const U& rhs) noexcept {
return detail::binary_visit<detail::greater_equal_impl>(lhs, rhs);
}
/// Does a field-by-field less equal comparison.
///
/// \returns `L < R || (L == R && tuple_size_v<T> <= tuple_size_v<U>)`, where `L` and
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
template <class T, class U>
constexpr bool le_fields(const T& lhs, const U& rhs) noexcept {
return detail::binary_visit<detail::less_equal_impl>(lhs, rhs);
}
/// Does a field-by-field hashing.
///
/// \returns combined hash of all the fields
template <class T>
std::size_t hash_fields(const T& x) {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
return detail::hash_impl<0, fields_count_val>::compute(detail::tie_as_tuple(x));
#else
std::size_t result = 0;
::boost::pfr::detail::for_each_field_dispatcher(
x,
[&result](const auto& lhs) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
result = detail::hash_impl<0, fields_count_val_lambda>::compute(lhs);
},
detail::make_index_sequence<fields_count_val>{}
);
return result;
#endif
}
}} // namespace boost::pfr
#endif // BOOST_PFR_OPS_HPP

View File

@@ -1,19 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_HPP
#define BOOST_PFR_PRECISE_HPP
/// \file boost/pfr/precise.hpp
/// Includes all the Boost.PFR headers that do not define `flat_*` functions, except \xmlonly<link linkend='header.boost.pfr.precise.global_ops_hpp'>boost/pfr/precise/global_ops.hpp</link>\endxmlonly
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/ops.hpp>
#include <boost/pfr/precise/io.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/precise/functions_for.hpp>
#endif // BOOST_PFR_PRECISE_HPP

View File

@@ -1,120 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_GLOBAL_OPS_HPP
#define BOOST_PFR_PRECISE_GLOBAL_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/io.hpp>
/// \file boost/pfr/precise/global_ops.hpp
/// Contains comparison operators and stream operators for any types that do not have their own operators.
/// If type is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/global_ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b defines:
/// @cond
namespace boost { namespace pfr { namespace detail {
template <class T, class U>
using enable_comparisons = std::enable_if_t<
std::is_same<T, U>::value,
bool
>;
}}} // namespace boost::pfr::detail
/// @endcond
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs);
template <class T> bool operator!=(const T& lhs, const T& rhs);
template <class T> bool operator< (const T& lhs, const T& rhs);
template <class T> bool operator> (const T& lhs, const T& rhs);
template <class T> bool operator<=(const T& lhs, const T& rhs);
template <class T> bool operator>=(const T& lhs, const T& rhs);
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost unordered containers and boost::hash<>.
template <class T> std::size_t hash_value(const T& value);
#else
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator==(const T& lhs, const U& rhs) {
return ::boost::pfr::equal_to<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator!=(const T& lhs, const U& rhs) {
return ::boost::pfr::not_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<(const T& lhs, const U& rhs) {
return ::boost::pfr::less<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>(const T& lhs, const U& rhs) {
return ::boost::pfr::greater<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<=(const T& lhs, const U& rhs) {
return ::boost::pfr::less_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>=(const T& lhs, const U& rhs) {
return ::boost::pfr::greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_ostream<Char, Traits>&
> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
::boost::pfr::write(out, value);
return out;
}
template <class Char, class Traits, class T>
static std::enable_if_t<
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
std::basic_istream<Char, Traits>&
> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
::boost::pfr::read(in, value);
return in;
}
template <class T>
static std::size_t hash_value(const T& value) {
return ::boost::pfr::hash<T>{}(value);
}
#endif
#endif // BOOST_PFR_PRECISE_GLOBAL_OPS_HPP

View File

@@ -1,110 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_IO_HPP
#define BOOST_PFR_PRECISE_IO_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#if BOOST_PFR_USE_CPP17
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
namespace boost { namespace pfr {
/// \brief Writes aggregate `value` to `out`
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
out << '{';
#if BOOST_PFR_USE_CPP17
detail::print_impl<0, fields_count_val>::print(out, detail::tie_as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&out](const auto& val) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
detail::print_impl<0, fields_count_val_lambda>::print(out, val);
},
detail::make_index_sequence<fields_count_val>{}
);
#endif
out << '}';
}
/// Reads aggregate `value` from stream `in`
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
template <class Char, class Traits, class T>
void read(std::basic_istream<Char, Traits>& in, T& value) {
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
#if BOOST_PFR_USE_CPP17
detail::read_impl<0, fields_count_val>::read(in, detail::tie_as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&in](const auto& val) {
// We can not reuse `fields_count_val` in lambda because compilers had issues with
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
detail::read_impl<0, fields_count_val_lambda>::read(in, val);
},
detail::make_index_sequence<fields_count_val>{}
);
#endif
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_IO_HPP

View File

@@ -1,147 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_OPS_HPP
#define BOOST_PFR_PRECISE_OPS_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/io.hpp>
/// \file boost/pfr/precise/ops.hpp
/// Contains comparison operators and stream operators for types that do not have their own operators.
/// If type is comparable or streamable using it's own operator or it's conversion operator, then the original operator is used.
///
/// Just write \b using \b namespace \b ops; and operators will be available in scope.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// using namespace ops;
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b contains:
namespace boost { namespace pfr {
namespace detail {
///////////////////// Helper typedef that it used by all the enable_not_*_comp_t
template <template <class, class> class Detector, class T>
using enable_not_comp_base_t = typename std::enable_if<
not_appliable<Detector, T const&, T const&>::value,
bool
>::type;
///////////////////// std::enable_if_t like functions that enable only if types do not support operation and are PODs
template <class T> using enable_not_eq_comp_t = enable_not_comp_base_t<comp_eq_detector, T>;
template <class T> using enable_not_ne_comp_t = enable_not_comp_base_t<comp_ne_detector, T>;
template <class T> using enable_not_lt_comp_t = enable_not_comp_base_t<comp_lt_detector, T>;
template <class T> using enable_not_le_comp_t = enable_not_comp_base_t<comp_le_detector, T>;
template <class T> using enable_not_gt_comp_t = enable_not_comp_base_t<comp_gt_detector, T>;
template <class T> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T>;
template <class Stream, class Type>
using enable_not_ostreamable_t = typename std::enable_if<
not_appliable<ostreamable_detector, Stream&, Type const&>::value,
Stream&
>::type;
template <class Stream, class Type>
using enable_not_istreamable_t = typename std::enable_if<
not_appliable<istreamable_detector, Stream&, Type&>::value,
Stream&
>::type;
} // namespace detail
namespace ops {
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost
template <class T> std::size_t hash_value(const T& value) noexcept;
#else
template <class T>
static detail::enable_not_eq_comp_t<T> operator==(const T& lhs, const T& rhs) noexcept {
return equal_to<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_ne_comp_t<T> operator!=(const T& lhs, const T& rhs) noexcept {
return not_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_lt_comp_t<T> operator<(const T& lhs, const T& rhs) noexcept {
return less<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_gt_comp_t<T> operator>(const T& lhs, const T& rhs) noexcept {
return greater<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_le_comp_t<T> operator<=(const T& lhs, const T& rhs) noexcept {
return less_equal<T>{}(lhs, rhs);
}
template <class T>
static detail::enable_not_ge_comp_t<T> operator>=(const T& lhs, const T& rhs) noexcept {
return greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static detail::enable_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
boost::pfr::write(out, value);
return out;
}
template <class Char, class Traits, class T>
static detail::enable_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
boost::pfr::read(in, value);
return in;
}
template <class T>
static std::enable_if_t<std::is_trivial<T>::value, std::size_t> hash_value(const T& value) noexcept {
return hash<T>{}(value);
}
#endif
} // namespace ops
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_OPS_HPP

View File

@@ -4,8 +4,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_TUPLE_SIZE_HPP
#define BOOST_PFR_PRECISE_TUPLE_SIZE_HPP
#ifndef BOOST_PFR_TUPLE_SIZE_HPP
#define BOOST_PFR_TUPLE_SIZE_HPP
#pragma once
#include <boost/pfr/detail/config.hpp>
@@ -16,13 +16,14 @@
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/fields_count.hpp>
/// \file boost/pfr/tuple_size.hpp
/// Contains tuple-like interfaces to get fields count \forcedlink{tuple_size}, \forcedlink{tuple_size_v}.
///
/// \b Synopsis:
namespace boost { namespace pfr {
/// Has a static const member variable `value` that contains fields count in a T.
/// Works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
/// Works for any T that supports aggregate initialization.
///
/// \b Example:
/// \code
@@ -33,10 +34,7 @@ using tuple_size = detail::size_t_< boost::pfr::detail::fields_count<T>() >;
/// `tuple_size_v` is a template variable that contains fields count in a T and
/// works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
/// works for any T that supports aggregate initialization.
///
/// \b Example:
/// \code
@@ -47,4 +45,4 @@ constexpr std::size_t tuple_size_v = tuple_size<T>::value;
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_TUPLE_SIZE_HPP
#endif // BOOST_PFR_TUPLE_SIZE_HPP

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=../../doc/html/boost_pfr.html">
<title>Boost.PFR</title>
</head>
<body>
<p>
Redirecting you to <a href="../../doc/html/boost_pfr.html">Boost.PFR</a>
</p>
</body>
</html>

17
meta/libraries.json Normal file
View File

@@ -0,0 +1,17 @@
{
"key": "pfr",
"name": "PFR",
"authors": [
"Antony Polukhin"
],
"maintainers": [
"Antony Polukhin <antoshkka -at- gmail.com>"
],
"description": "Basic reflection for user defined types.",
"category": [
"Data",
"Metaprogramming"
],
"std": [ "proposal" ],
"cxxstd": "14"
}

View File

@@ -50,7 +50,7 @@ constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = 0) noexcept {
auto& [a] = val;
auto& [a] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a);
}
@@ -65,7 +65,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class<
############################################################################################################################
EPILOGUE = """
template <class T, std::size_t I>
constexpr void tie_as_tuple(T& val, size_t_<I>) noexcept {
constexpr void tie_as_tuple(T& /*val*/, size_t_<I>) noexcept {
static_assert(sizeof(T) && false,
"====================> Boost.PFR: Too many fields in a structure T. Regenerate include/boost/pfr/detail/core17_generated.hpp file for appropriate count of fields. For example: `python ./misc/generate_cpp17.py 300 > include/boost/pfr/detail/core17_generated.hpp`");
}
@@ -79,33 +79,33 @@ constexpr void tie_as_tuple(T& val, size_t_<I>) noexcept {
indexes = " a"
print PROLOGUE
print(PROLOGUE)
funcs_count = 100 if len(sys.argv) == 1 else int(sys.argv[1])
max_args_on_a_line = len(ascii_letters)
for i in xrange(1, funcs_count):
for i in range(1, funcs_count):
if i % max_args_on_a_line == 0:
indexes += ",\n "
else:
indexes += ","
if i >= max_args_on_a_line:
indexes += ascii_letters[i / max_args_on_a_line - 1]
indexes += ascii_letters[i // max_args_on_a_line - 1]
indexes += ascii_letters[i % max_args_on_a_line]
print "template <class T>"
print "constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {"
print("template <class T>")
print("constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {")
if i < max_args_on_a_line:
print " auto& [" + indexes.strip() + "] = val;"
print " return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");"
print(" auto& [" + indexes.strip() + "] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
print(" return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");")
else:
print " auto& ["
print indexes
print " ] = val;"
print ""
print " return ::boost::pfr::detail::make_tuple_of_references("
print indexes
print " );"
print(" auto& [")
print(indexes)
print(" ] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
print("")
print(" return ::boost::pfr::detail::make_tuple_of_references(")
print(indexes)
print(" );")
print "}\n"
print("}\n")
print EPILOGUE
print(EPILOGUE)

View File

@@ -5,6 +5,7 @@
# http://www.boost.org/LICENSE_1_0.txt)
#
import python ;
import testing ;
import ../../config/checks/config : requires ;
@@ -12,184 +13,122 @@ project
: source-location .
: requirements
<toolset>msvc:<cxxflags>"/std:c++latest"
<toolset>msvc:<define>BOOST_PFR_USE_CPP17=1
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
[ requires cxx14_constexpr ]
;
########## BEGIN of helpers to detect Loophole trick support
actions mp_simple_run_action
{
$(>) > $(<)
}
rule mp-run-simple ( sources + : args * : input-files * : requirements * : target-name )
{
exe $(target-name)_exe : $(sources) : $(requirements) ;
explicit $(target-name)_exe ;
make $(target-name).output : $(target-name)_exe : @mp_simple_run_action ;
explicit $(target-name).output ;
alias $(target-name) : $(target-name).output ;
}
mp-run-simple loophole_detection.cpp : : : : compiler_supports_loophole ;
explicit compiler_supports_loophole ;
########## END of helpers to detect Loophole trick support
local DISABLE_ON_MSVC = <toolset>msvc:<build>no ;
local DISABLE_ON_CLANG8_PLUS = <toolset>clang-8:<build>no <toolset>clang-9:<build>no <toolset>clang-10:<build>no ;
local LOOPHOLE_FLAT_DEF = <define>BOOST_PFR_TEST_FLAT <define>BOOST_PFR_USE_LOOPHOLE=1 $(DISABLE_ON_MSVC) $(DISABLE_ON_CLANG8_PLUS) ;
local CLASSIC_FLAT_DEF = <define>BOOST_PFR_TEST_FLAT <define>BOOST_PFR_USE_LOOPHOLE=0 $(DISABLE_ON_MSVC) ;
local LOOPHOLE_PREC_DEF = <define>BOOST_PFR_TEST_PRECISE <define>BOOST_PFR_USE_LOOPHOLE=1 $(DISABLE_ON_MSVC) $(DISABLE_ON_CLANG8_PLUS) ;
local CLASSIC_PREC_DEF = <define>BOOST_PFR_TEST_PRECISE <define>BOOST_PFR_USE_LOOPHOLE=0 ;
test-suite pfr
:
##### Common tests
[ run common/offset_based_getter.cpp ]
[ run common/ops.cpp : : : $(CLASSIC_FLAT_DEF) : flat_ops ]
[ run common/ops.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_ops ]
[ run common/ops.cpp : : : $(CLASSIC_PREC_DEF) : precise_ops ]
[ run common/ops.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_ops ]
[ run common/global_ops.cpp : : : $(CLASSIC_FLAT_DEF) : flat_global_ops ]
[ run common/global_ops.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_global_ops ]
[ run common/global_ops.cpp : : : $(CLASSIC_PREC_DEF) : precise_global_ops ]
[ run common/global_ops.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_global_ops ]
[ run common/functions_for.cpp : : : $(CLASSIC_FLAT_DEF) : flat_function_for ]
[ run common/functions_for.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_function_for ]
[ run common/functions_for.cpp : : : $(CLASSIC_PREC_DEF) : precise_function_for ]
[ run common/functions_for.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_function_for ]
[ run common/read_write.cpp : : : $(CLASSIC_FLAT_DEF) : flat_read_write ]
[ run common/read_write.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_read_write ]
[ run common/read_write.cpp : : : $(CLASSIC_PREC_DEF) : precise_read_write ]
[ run common/read_write.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_read_write ]
[ run common/std_interactions.cpp : : : $(CLASSIC_FLAT_DEF) : flat_std_interactions ]
[ run common/std_interactions.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_std_interactions ]
[ run common/std_interactions.cpp : : : $(CLASSIC_PREC_DEF) : precise_std_interactions ]
[ run common/std_interactions.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_std_interactions ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(CLASSIC_FLAT_DEF) : flat_movable_and_lvalue_references ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_movable_and_lvalue_references ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(CLASSIC_PREC_DEF) : precise_movable_and_lvalue_references ]
[ compile-fail common/movable_and_lvalue_references.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_movable_and_lvalue_references ]
[ compile-fail common/private_fields.cpp : $(CLASSIC_FLAT_DEF) : flat_private_fields ]
[ compile-fail common/private_fields.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_private_fields ]
[ compile-fail common/private_fields.cpp : $(CLASSIC_PREC_DEF) : precise_private_fields ]
[ compile-fail common/private_fields.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_private_fields ]
[ compile-fail common/protected_fields.cpp : $(CLASSIC_FLAT_DEF) : flat_protected_fields ]
[ compile-fail common/protected_fields.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_protected_fields ]
[ compile-fail common/protected_fields.cpp : $(CLASSIC_PREC_DEF) : precise_protected_fields ]
[ compile-fail common/protected_fields.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_protected_fields ]
[ compile-fail common/virtual_functions.cpp : $(CLASSIC_FLAT_DEF) : flat_virtual_functions ]
[ compile-fail common/virtual_functions.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_virtual_functions ]
[ compile-fail common/virtual_functions.cpp : $(CLASSIC_PREC_DEF) : precise_virtual_functions ]
[ compile-fail common/virtual_functions.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_virtual_functions ]
[ compile-fail common/ops_on_union.cpp : $(CLASSIC_FLAT_DEF) : flat_on_union ]
[ compile-fail common/ops_on_union.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_on_union ]
[ compile-fail common/ops_on_union.cpp : $(CLASSIC_PREC_DEF) : precise_on_union ]
[ compile-fail common/ops_on_union.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_on_union ]
[ compile-fail common/ops_unions.cpp : $(CLASSIC_FLAT_DEF) : flat_unions ]
[ compile-fail common/ops_unions.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_unions ]
[ compile-fail common/ops_unions.cpp : $(CLASSIC_PREC_DEF) : precise_unions ]
[ compile-fail common/ops_unions.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(CLASSIC_FLAT_DEF) : flat_unrestricted_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_unrestricted_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(CLASSIC_PREC_DEF) : precise_unrestricted_unions ]
[ compile-fail common/ops_unrestricted_unions.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_unrestricted_unions ]
[ compile-fail common/non_std_layout.cpp : $(CLASSIC_FLAT_DEF) : flat_non_standard_layout ]
[ compile-fail common/non_std_layout.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_standard_layout ]
[ run common/non_std_layout.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_standard_layout ]
[ run common/non_std_layout.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_standard_layout ]
[ compile-fail common/non_default_constructible.cpp : $(CLASSIC_FLAT_DEF) : flat_non_default_constructible ]
[ compile-fail common/non_default_constructible.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_sdefault_constructible ]
[ run common/non_default_constructible.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_default_constructible ]
[ run common/non_default_constructible.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_default_constructible ]
#[ compile-fail common/non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_copyable_but_movable ]
#[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_copyable_but_movable ]
[ run common/non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_copyable_but_movable ]
[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_copyable_but_movable ]
#[ compile-fail common/non_default_constructible_non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_dc_non_cop_but_mov ]
#[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_dc_non_cop_but_mov ]
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_dc_non_cop_but_mov ]
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_dc_non_cop_but_mov ]
[ compile-fail common/fields_count_on_reference.cpp ]
[ run common/fields_count_on_const.cpp ]
##### Flat tuple sizes
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON=void* : test_tuple_sizes_on_voidptrs ]
[ run common/test_tuple_sizes_on.cpp : : : $(DISABLE_ON_MSVC) <define>BOOST_PFR_RUN_TEST_ON="std::size_t" : test_tuple_sizes_on_size_ts ]
#[ run common/test_tuple_sizes_on.cpp $(DISABLE_ON_MSVC)<define>BOOST_PFR_RUN_TEST_ON=char <define>BOOST_PFR_RUN_HUGE_TESTS : test_tuple_sizes_on_chars_huge ]
##### Flat specific tests
[ run flat/core.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/flat_tuple_size.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/flat_motivating_example.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/flat_for_each_field.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ run flat/destructuring_tie.cpp : : : $(CLASSIC_FLAT_DEF) ]
[ compile-fail flat/flat_tuple_size_on_non_aggregate.cpp : $(CLASSIC_FLAT_DEF) ]
[ compile-fail flat/flat_tuple_size_on_bitfields.cpp : $(CLASSIC_FLAT_DEF) ]
##### Precise specific tests
[ run precise/tuple_size.cpp : : : $(CLASSIC_PREC_DEF) : precise_tuple_size ]
[ run precise/bitfields.cpp : : : $(CLASSIC_PREC_DEF) : precise_tuple_size_on_bitfields ]
[ run precise/for_each_field.cpp : : : $(CLASSIC_PREC_DEF) : precise_for_each_field ]
[ run precise/motivating_example0.cpp : : : $(CLASSIC_PREC_DEF) : precise_motivating_example0 ]
[ run precise/motivating_example.cpp : : : $(CLASSIC_PREC_DEF) : precise_motivating_example ]
[ run precise/motivating_example2.cpp : : : $(CLASSIC_PREC_DEF) : precise_motivating_example2 ]
[ run precise/optional_like.cpp : : : $(CLASSIC_PREC_DEF) : precise_optional_like ]
[ run precise/get_non_default_constructible.cpp : : : $(CLASSIC_PREC_DEF) : precise_get_non_default_constructible ]
[ run precise/destructuring_tie.cpp : : : $(CLASSIC_PREC_DEF) : precise_destructuring_tie ]
[ run precise/error_pfr_c1202.cpp : : : $(CLASSIC_PREC_DEF) : precise_c1202_issue21 ]
[ compile-fail precise/non_aggregate.cpp : $(CLASSIC_PREC_DEF) : precise_non_aggregate ]
[ run precise/tie_anonymous.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_tie_anonymous ]
# See "Requirements and Limitations" section of the docs for info on following tests:
#[ compile-fail precise/template_constructor.cpp : $(CLASSIC_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_template_constructor14 ]
#[ compile-fail precise/template_unconstrained.cpp : $(CLASSIC_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_template_unconstrained14 ]
[ run precise/template_constructor.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_template_constructor ]
# TODO:
#[ run precise/template_unconstrained.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_template_unconstrained ]
# The following tests may compile of fail depending on C++ Standard version.
#[ compile-fail precise/issue30.cpp : $(CLASSIC_PREC_DEF) : precise_issue30 ]
#[ compile-fail precise/issue33.cpp : $(CLASSIC_PREC_DEF) : precise_issue33 ]
##### Loophole tests running precise and flat specific tests
[ run flat/core.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_core ]
[ run flat/flat_tuple_size.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_tuple_size ]
[ run flat/flat_motivating_example.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_motivating_example ]
[ run flat/flat_for_each_field.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_for_each_field ]
[ compile-fail flat/flat_tuple_size_on_non_aggregate.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_tuple_size_on_non_aggregate ]
[ compile-fail flat/flat_tuple_size_on_bitfields.cpp : $(LOOPHOLE_FLAT_DEF) : flat_lh_tuple_size_on_bitfields ]
[ run precise/tuple_size.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_tuple_size ]
[ run precise/bitfields.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_tuple_size_on_bitfields ]
[ run precise/for_each_field.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_for_each_field ]
[ run precise/motivating_example0.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_motivating_example0 ]
[ run precise/motivating_example.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_motivating_example ]
[ run precise/motivating_example2.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_motivating_example2 ]
[ run precise/optional_like.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_optional_like ]
[ run precise/get_non_default_constructible.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_get_non_default_constructible ]
[ run precise/error_pfr_c1202.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_c1202_issue21 ]
[ run precise/issue30.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue30 ]
[ run precise/issue33.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue33 ]
[ compile-fail precise/non_aggregate.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_non_aggregate ]
[ run precise/tie_anonymous.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_tie_anonymous ]
# See "Requirements and Limitations" section of the docs for info on following tests:
#[ compile-fail precise/template_constructor.cpp : $(LOOPHOLE_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_lh_template_constructor14 ]
#[ compile-fail precise/template_unconstrained.cpp : $(LOOPHOLE_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_lh_template_unconstrained14 ]
[ run precise/template_constructor.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_template_constructor ]
# TODO:
#[ run precise/template_unconstrained.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_template_unconstrained ]
# Examples from docs
[ run ../example/examples.cpp : : : $(DISABLE_ON_MSVC) ]
[ run ../example/quick_examples.cpp : : : $(DISABLE_ON_MSVC) ]
local REQUIRE_LOOPHOLE =
[ check-target-builds ../test//compiler_supports_loophole : : <build>no ]
;
local STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=1 [ requires cxx17_structured_bindings ] ;
local LOOPHOLE_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=1 <define>BOOST_PFR_USE_CPP17=0 $(REQUIRE_LOOPHOLE) ;
local CLASSIC_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 $(DISABLE_ON_MSVC) ;
test-suite pfr_tests
:
[ run print_config.cpp : : : <test-info>always_show_run_output : auto_engine_config ]
[ run offset_based_getter.cpp ]
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ]
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ]
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ]
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=void* : test_tuple_sizes_on_voidptrs ]
[ run test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON="std::size_t" : test_tuple_sizes_on_size_ts ]
[ run run/motivating_example.cpp : : : : auto_engine_motivating ]
[ run ../example/sample_printing.cpp : : : : auto_engine_sample_printing ]
[ run ../example/get.cpp : : : : auto_engine_get ]
[ run ../example/quick_examples.cpp : : : : auto_engine_quick ]
;
local BLACKLIST_TESTS_FOR_LOOPHOLE =
constexpr_ops # Loophole is not constexpr usable because of the reinterpret_cast usage
get_const_field # boost::pfr::get gives compile time error on const fields
optional_chrono # boost::pfr::* has problems with std::optional, produces compile time error
template_constructor # Template constructor in one of the fields of the aggregate
tie_anonymous_const_field # boost::pfr::structure_tie gives compile time error on const fields
;
# Those tests are either
# * reflecting a non literal type
# * or calling boost::pfr::get and the result is a user defined structure
local BLACKLIST_TESTS_FOR_CLASSIC =
constexpr_ops
get_const_field
get_non_default_constructible
get_rvalue
issue30
issue33
motivating_example0
motivating_example2
optional_chrono
optional_like
read_write_non_literal
template_constructor
template_forwarding_ref
template_unconstrained
tie_anonymous
tie_anonymous_const_field
;
for local source_file in [ glob ./run/*.cpp ] [ glob ../example/*.cpp ]
{
local target_name = $(source_file[1]:B) ;
pfr_tests += [ run $(source_file) : : : $(STRUCTURED_BINDING_ENGINE) : $(target_name)_sb ] ;
if ! $(target_name) in $(BLACKLIST_TESTS_FOR_LOOPHOLE)
{
pfr_tests += [ run $(source_file) : : : $(LOOPHOLE_ENGINE) : $(target_name)_lh ] ;
}
else
{
pfr_tests += [ compile-fail $(source_file) : $(LOOPHOLE_ENGINE) : $(target_name)_lh ] ;
}
if ! $(target_name) in $(BLACKLIST_TESTS_FOR_CLASSIC)
{
pfr_tests += [ run $(source_file) : : : $(CLASSIC_ENGINE) : $(target_name)_classic ] ;
}
else
{
pfr_tests += [ compile-fail $(source_file) : $(CLASSIC_ENGINE) : $(target_name)_classic ] ;
}
}
for local source_file in [ glob ./compile-fail/*.cpp ]
{
local target_name = $(source_file[1]:B) ;
pfr_tests += [ compile-fail $(source_file) : $(STRUCTURED_BINDING_ENGINE) : $(target_name)_sb ] ;
pfr_tests += [ compile-fail $(source_file) : $(LOOPHOLE_ENGINE) : $(target_name)_lh ] ;
pfr_tests += [ compile-fail $(source_file) : $(CLASSIC_ENGINE) : $(target_name)_classic ] ;
}
if [ python.configured ]
{
testing.make-test run-pyd : ../misc/generate_cpp17.py ;
}

View File

@@ -11,13 +11,17 @@
# File revision #6 (with DIFF)
init:
- set BOOST_REMOVE=%APPVEYOR_PROJECT_NAME% # Remove this folder from lib from full clone of Boost.
# boost-local/libs/ folder to put this library into. This may be useful, if you're for example running Travis
# from `Boost.DLL` repo while Boost already has `dll` and with to replace `dll` with content of`Boost.DLL`.
#
# Otherwise just leave the default value - set BOOST_LIBS_FOLDER=%APPVEYOR_PROJECT_NAME%
- set BOOST_LIBS_FOLDER=pfr # DIFF
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
version: 1.64.{build}-{branch}
version: 1.74.{build}-{branch}
# branches to build
branches:
@@ -28,6 +32,10 @@ skip_tags: true
environment:
matrix:
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
# TOOLSET: msvc # TODO: clang-win ???
# ADDRMD: 32,64
# CXXSTD: 17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc # clang-win has problems with structured bindings - it can not correclty use std::tuple_size
ADDRMD: 32,64
@@ -60,22 +68,22 @@ environment:
before_build:
- set BOOST_BRANCH=develop
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
- echo "Testing %APPVEYOR_PROJECT_NAME%"
- echo "Testing %BOOST_LIBS_FOLDER%"
# Cloning Boost libraries (fast nondeep cloning)
- set BOOST=C:/boost-local
- git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git %BOOST%
- cd %BOOST%
- git submodule update --init --depth 10 tools/build tools/boostdep libs/type_index # DIFF: Added libs/type_index
- git submodule update --init --depth 10 tools/build tools/boostdep
- rm -rf %BOOST%/libs/%BOOST_REMOVE%
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%APPVEYOR_PROJECT_NAME%
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" %APPVEYOR_PROJECT_NAME%
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" type_index # DIFF: Added
- echo "rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%"
- rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%BOOST_LIBS_FOLDER%
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" -I example -I examples %BOOST_LIBS_FOLDER%
build_script:
- cmd /c bootstrap
- b2.exe headers
- cd %BOOST%/libs/%APPVEYOR_PROJECT_NAME%/test
- cd %BOOST%/libs/%BOOST_LIBS_FOLDER%/test
after_build:
before_test:

View File

@@ -1,126 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
# include <boost/pfr/flat/global_ops.hpp>
#elif defined(BOOST_PFR_TEST_PRECISE)
# include <boost/pfr/precise/global_ops.hpp>
#else
# error Misused test
#endif
#include <boost/core/lightweight_test.hpp>
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <string>
#include <unordered_set>
#define BOOST_HASH_NO_EXTENSIONS
#include <boost/container_hash/hash.hpp>
template <class T>
void test_comparable_struct() {
T s1 {0, 1, false, 6,7,8,9,10,11};
T s2 = s1;
T s3 {0, 1, false, 6,7,8,9,10,11111};
BOOST_TEST(s1 == s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
BOOST_TEST(!(s1 != s2));
BOOST_TEST(!(s1 == s3));
BOOST_TEST(s1 != s3);
BOOST_TEST(s1 < s3);
BOOST_TEST(s3 > s2);
BOOST_TEST(s1 <= s3);
BOOST_TEST(s3 >= s2);
std::cout << s1 << std::endl;
T s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
BOOST_TEST(s1 == s4);
int i = 1, j = 2;
BOOST_TEST_NE(i, j);
}
void test_empty_struct() {
struct empty {};
std::cout << empty{};
BOOST_TEST(empty{} == empty{});
}
struct adl_hash {
template <class T>
std::size_t operator()(const T& val) const {
using namespace boost;
return hash_value(val);
}
};
template <class Comparator>
void test_with_contatiners() {
struct testing { bool b1, b2; int i; };
std::set<testing, Comparator > t{
{true, true, 100},
{false, true, 100},
{true, false, 100},
{true, true, 101}
};
BOOST_TEST(t.find({true, true, 100}) != t.end());
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
std::unordered_set<testing, adl_hash> us(t.begin(), t.end());
BOOST_TEST_EQ(us.size(), t.size());
}
namespace foo {
struct comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
}
void test_implicit_conversions() {
std::stringstream ss;
ss << std::true_type{};
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion :(
}
int main() {
test_comparable_struct<foo::comparable_struct>();
struct local_comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
test_comparable_struct<local_comparable_struct>();
test_empty_struct();
#ifndef BOOST_CLANG
// TODO: Fails for unknown reason on Clang
test_with_contatiners<std::less<>>();
test_with_contatiners<std::greater<>>();
#endif
test_implicit_conversions();
return boost::report_errors();
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) 2018 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
using namespace boost::pfr::flat_ops;
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
using namespace boost::pfr::ops;
#endif
union test_union {
const char* c;
int i;
};
int main() {
test_union v{""};
return v == v;
}

View File

@@ -1,126 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/precise/core.hpp>
template <class T1, std::size_t CountInT, std::size_t CountHelpers>
void test_counts_on_multiple_chars_impl_1() {
using boost::pfr::flat_tuple_size_v;
using boost::pfr::tuple_size_v;
struct t1_c { T1 v1; char c[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_c> == CountInT + CountHelpers, "");
struct t1_s { T1 v1; short s[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_s> == CountInT + CountHelpers, "");
struct t1_i { T1 v1; const int i[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_i> == CountInT + CountHelpers, "");
struct t1_p { T1 v1; void* p[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_p> == CountInT + CountHelpers, "");
struct t1_ll { T1 v1; long long ll[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_ll> == CountInT + CountHelpers, "");
struct rt1_c { char c[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_c> == CountInT + CountHelpers, "");
struct rt1_s { const short s[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_s> == CountInT + CountHelpers, "");
struct rt1_i { int i[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_i> == CountInT + CountHelpers, "");
struct rt1_p { void* p[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_p> == CountInT + CountHelpers, "");
struct rt1_ll { long long ll[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_ll> == CountInT + CountHelpers, "");
struct rt1_ll_1 { rt1_ll v1; };
static_assert(flat_tuple_size_v<rt1_ll_1> == CountInT + CountHelpers, "");
static_assert(tuple_size_v<rt1_ll_1> == 1, "");
}
template <class T1, std::size_t CountInT>
void test_counts_on_multiple_chars_impl() {
using boost::pfr::flat_tuple_size_v;
using boost::pfr::tuple_size_v;
struct t1_0 { T1 v1; };
static_assert(flat_tuple_size_v<t1_0> == CountInT, "");
static_assert(flat_tuple_size_v<T1> == CountInT, "");
static_assert(flat_tuple_size_v<std::conditional_t<std::is_fundamental<T1>::value, T1*, void*> > == 1, "");
#if !defined(__GNUC__) || __GNUC__ != 8
// GCC-8 has big problems with this test:
// error: 'constexpr ubiq_constructor::operator Type&() const [with Type = test_counts_on_multiple_chars()::t2*]',
// declared using local type 'test_counts_on_multiple_chars()::t2', is used but never defined [-fpermissive]
//
// Fixed in GCC-9.
static_assert(tuple_size_v<T1*> == 1, "");
#endif
struct t1_0_1 { t1_0 t1; };
static_assert(flat_tuple_size_v<t1_0_1> == CountInT, "");
static_assert(tuple_size_v<t1_0_1> == 1, "");
struct t1_0_2 { t1_0 t1; t1_0 t2; };
static_assert(flat_tuple_size_v<t1_0_2> == CountInT * 2, "");
static_assert(tuple_size_v<t1_0_2> == 2, "");
static_assert(flat_tuple_size_v<T1[5]> == CountInT * 5, "");
test_counts_on_multiple_chars_impl_1<T1, CountInT, 1>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 2>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 3>();
#ifdef BOOST_PFR_RUN_HUGE_TESTS
test_counts_on_multiple_chars_impl_1<T1, CountInT, 4>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 5>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 6>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 7>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 8>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 9>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 10>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 11>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 12>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 13>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 14>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 15>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 16>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 17>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 18>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 19>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 20>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 23>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 24>();
#endif
}
template <class T>
void test_counts_on_multiple_chars() {
using boost::pfr::tuple_size_v;
test_counts_on_multiple_chars_impl<T, 1>();
struct t2 { T v1; T v2; };
static_assert(tuple_size_v<t2> == 2, "");
test_counts_on_multiple_chars_impl<t2, 2>();
test_counts_on_multiple_chars_impl<T[2], 2>();
test_counts_on_multiple_chars_impl<T[3], 3>();
test_counts_on_multiple_chars_impl<T[4], 4>();
struct t8 { T v1; T v2; T v3; T v4; T v5; T v6; T v7; T v8; };
test_counts_on_multiple_chars_impl<t8, 8>();
}
int main() {
test_counts_on_multiple_chars< BOOST_PFR_RUN_TEST_ON >();
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -11,5 +11,5 @@ struct some_struct {
};
int main() {
return boost::pfr::detail::fields_count<some_struct&>();
return static_cast<int>(boost::pfr::detail::fields_count<some_struct&>());
}

View File

@@ -1,10 +1,9 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/tuple_size.hpp>
struct X {
X() = default;
@@ -21,10 +20,6 @@ struct test_lvalue_ref_and_movable {
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_lvalue_ref_and_movable>::value;
#else
return boost::pfr::tuple_size<test_lvalue_ref_and_movable>::value;
#endif
}

View File

@@ -3,7 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <tuple>

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <string>
#include <boost/pfr/ops.hpp>
union test_union {
const char* c;
int i;
};
int main() {
test_union v{""};
return boost::pfr::eq(v, v);
}

View File

@@ -1,19 +1,11 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
using namespace boost::pfr::flat_ops;
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
using namespace boost::pfr::ops;
#endif
#include <boost/pfr/ops.hpp>
union test_union {
const char* c;
@@ -26,5 +18,5 @@ int main() {
};
two_unions v{{""}, {""}};
return v == v;
return boost::pfr::eq(v, v);
}

View File

@@ -1,18 +1,14 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/ops.hpp>
#include <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
using namespace boost::pfr::flat_ops;
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
using namespace boost::pfr::ops;
#if defined(_MSC_VER)
# pragma warning( disable: 4624 ) // destructor was implicitly defined as deleted
#endif
union test_unrestricted_union {
@@ -28,5 +24,5 @@ int main() {
// Not calling the destructor intentionally!
auto v = new two_unions{{1}, {1}};
return *v == *v;
return boost::pfr::eq(*v, *v);
}

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2020 Antony Polukhin
// Copyright (c) 2020 Richard Hodges
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Test case from https://github.com/madmongo1/pfr_review/blob/master/pre-cxx20/test-2.cpp
#include <boost/pfr/functions_for.hpp>
#include <boost/utility/string_view.hpp>
#include <sstream>
#include <string>
#include <boost/core/lightweight_test.hpp>
namespace the_wild {
struct animal {
std::string name;
boost::string_view temperament;
};
// Error: std::hash not specialized for type
// OR in C++14:
// Error: animal is not constexpr initializable
BOOST_PFR_FUNCTIONS_FOR(animal)
} // namespace the_wild
const auto fido = the_wild::animal { "fido", "aloof" };
int main() {
std::ostringstream oss;
oss << fido;
BOOST_TEST_EQ(oss.str(), "{\"fido\", \"aloof\"}");
return boost::report_errors();
}

View File

@@ -1,10 +1,14 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/tuple_size.hpp>
#ifdef __clang__
# pragma clang diagnostic ignored "-Wunused-private-field"
#endif
class test_with_private {
private:
@@ -17,15 +21,10 @@ public:
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_private>::value;
#else
#ifndef __cpp_lib_is_aggregate
# error No known way to detect private fields.
#endif
return boost::pfr::tuple_size<test_with_private>::value;
#endif
}

View File

@@ -1,10 +1,9 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/tuple_size.hpp>
class test_with_protected {
protected:
@@ -17,15 +16,11 @@ public:
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_protected>::value;
#else
#ifndef __cpp_lib_is_aggregate
// TODO: No known way to detect protected fields
# error No known way to detect protected fields.
#endif
return boost::pfr::tuple_size<test_with_protected>::value;
#endif
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/core.hpp>
#include <string>
struct test_struct {
int i;
std::string s;
};
int main() {
boost::pfr::structure_tie(test_struct{1, "test"});
}

View File

@@ -1,10 +1,9 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/tuple_size.hpp>
struct test_with_virtual {
int i = 0;
@@ -16,10 +15,6 @@ struct test_with_virtual {
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_virtual>::value;
#else
return boost::pfr::tuple_size<test_with_virtual>::value;
#endif
}

View File

@@ -1,709 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//#define BOOST_PFR_RELAX_POD_REQUIREMENT
#include <boost/pfr.hpp>
#include <boost/core/lightweight_test.hpp>
//#include <boost/type_index.hpp> // for debugging
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <cstring>
using namespace boost::pfr;
template <std::size_t I, class T>
void print(T& f) {
std::cout << flat_get<I>(f) << "\t\t"
<< typeid(flat_tuple_element_t<I, T>).name()
<< std::endl;
}
struct make_my_life_harder { int a0; short a1; };
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
struct foo {
unsigned char v0;
unsigned int v1;
unsigned short v2;
unsigned long long v3;
unsigned char v4and5[2];
int v6;
std::size_t v7;
int* v8;
const void* v9;
int const**const volatile**volatile** v10;
const double v11;
make_my_life_harder v12and13;
make_my_life_even_more_harder v14and15andv16and17;
};
void test_print() {
foo f {
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
, {18, 19}
, {20, 21, {22, 23}}
};
print<0>(f); print<1>(f); print<2>(f);
print<3>(f); print<4>(f); print<5>(f);
print<6>(f); print<7>(f); print<8>(f);
print<9>(f); print<10>(f); print<11>(f);
print<12>(f); print<13>(f); print<14>(f);
print<15>(f); print<16>(f); print<17>(f);
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
int a[] = {0, 1, 2, 3};
std::cout << '\n' << flat_get<1>(a) << std::endl;
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
std::cout << flat_get<4>(b) << std::endl;
int i = 777;
std::cout << flat_get<0>(i) << std::endl;
}
void test_runtime(const foo& f) {
BOOST_TEST_EQ( flat_get<0>(f), f.v0);
BOOST_TEST_EQ( flat_get<1>(f), f.v1);
BOOST_TEST_EQ( flat_get<2>(f), f.v2);
BOOST_TEST_EQ( flat_get<3>(f), f.v3);
BOOST_TEST_EQ( flat_get<4>(f), f.v4and5[0]);
BOOST_TEST_EQ( flat_get<5>(f), f.v4and5[1]);
BOOST_TEST_EQ( flat_get<6>(f), f.v6);
BOOST_TEST_EQ( flat_get<7>(f), f.v7);
BOOST_TEST_EQ( flat_get<8>(f), f.v8);
BOOST_TEST_EQ( flat_get<9>(f), f.v9);
BOOST_TEST_EQ( flat_get<10>(f), f.v10);
BOOST_TEST( flat_get<11>(f) < f.v11 + 0.001); BOOST_TEST( flat_get<11>(f) > f.v11 - 0.001);
BOOST_TEST_EQ( flat_get<12>(f), f.v12and13.a0);
BOOST_TEST_EQ( flat_get<13>(f), f.v12and13.a1);
BOOST_TEST_EQ( flat_get<14>(f), f.v14and15andv16and17.b0);
BOOST_TEST_EQ( flat_get<15>(f), f.v14and15andv16and17.b1);
BOOST_TEST_EQ( flat_get<16>(f), f.v14and15andv16and17.cr.a0);
BOOST_TEST_EQ( flat_get<17>(f), f.v14and15andv16and17.cr.a1);
}
template <class T>
void test_compiletime() {
constexpr T f{};
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
}
template <class T>
constexpr void test_compiletime_array() {
{
constexpr T f[20] = {0};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
{
constexpr T f[2][10] = {{0}};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
{
constexpr T f[2][5][2] = {{{0}}};
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
}
}
void test_with_enums() {
enum class my_enum: unsigned {
VALUE1 = 17, VALUE2, VALUE3
};
struct my_struct { my_enum e; int i; short s; };
my_struct s {my_enum::VALUE1, 10, 11};
std::tuple<unsigned, int, short> t = flat_structure_to_tuple(s);
BOOST_TEST_EQ(std::get<0>(t), 17u);
BOOST_TEST_EQ(std::get<1>(t), 10);
BOOST_TEST_EQ(std::get<2>(t), 11);
flat_get<1>(s) = 101;
BOOST_TEST_EQ(flat_get<1>(s), 101);
flat_get<2>(s) = 111;
BOOST_TEST_EQ(flat_get<2>(s), 111);
BOOST_TEST(flat_structure_tie(s) == flat_structure_tie(s));
BOOST_TEST(flat_structure_tie(s) == flat_structure_to_tuple(s));
BOOST_TEST(flat_structure_tie(s) != t);
flat_structure_tie(s) = t;
BOOST_TEST_EQ(flat_get<0>(s), 17u);
BOOST_TEST_EQ(flat_get<1>(s), 10);
BOOST_TEST_EQ(flat_get<2>(s), 11);
static_assert(std::is_same<
int, flat_tuple_element_t<1, my_struct>
>::value, "");
static_assert(std::is_same<
short, flat_tuple_element_t<2, my_struct>
>::value, "");
static_assert(std::is_same<
const int, flat_tuple_element_t<1, const my_struct>
>::value, "");
static_assert(std::is_same<
volatile short, flat_tuple_element_t<2, volatile my_struct>
>::value, "");
static_assert(std::is_same<
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
>::value, "");
static_assert(
3 == flat_tuple_size_v<const volatile my_struct>,
""
);
}
void test_comparable_struct() {
struct comparable_struct {
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
};
using namespace flat_ops;
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
comparable_struct s2 = s1;
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
BOOST_TEST(s1 == s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
BOOST_TEST(!(s1 != s2));
BOOST_TEST(!(s1 == s3));
BOOST_TEST(s1 != s3);
BOOST_TEST(s1 < s3);
BOOST_TEST(s3 > s2);
BOOST_TEST(s1 <= s3);
BOOST_TEST(s3 >= s2);
std::cout << s1 << std::endl;
comparable_struct s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
BOOST_TEST(s1 == s4);
int i = 1, j = 2;
BOOST_TEST_NE(i, j);
}
void test_empty_struct() {
struct empty {};
using namespace flat_ops;
std::cout << empty{} << std::endl;
BOOST_TEST(empty{} == empty{});
}
void test_pods_with_int_operators() {
using namespace flat_ops;
std::stringstream ss;
ss << std::is_pod<int>{};
int i = 0;
ss >> i;
BOOST_TEST_EQ(i, 1);
std::cout << i << std::endl;
}
void test_struct_with_single_field() {
struct f1 { int i; };
using namespace flat_ops;
std::stringstream ss;
ss << f1{ 777 };
f1 var{};
ss >> var;
BOOST_TEST_EQ(var.i, 777);
BOOST_TEST(var == f1{ 777 });
BOOST_TEST(var != f1{ 778 });
BOOST_TEST(var <= f1{ 777 });
BOOST_TEST(var <= f1{ 778 });
BOOST_TEST(var < f1{ 778 });
BOOST_TEST(var >= f1{ 777 });
BOOST_TEST(var >= f1{ 776 });
BOOST_TEST(var > f1{ 776 });
}
template <class Comparator>
void test_with_contatiners() {
struct testing { bool b1, b2; int i; };
struct testing2 { bool b1, b2; int i; };
std::set<testing, Comparator > t{
{true, true, 100},
{false, true, 100},
{true, false, 100},
{true, true, 101}
};
BOOST_TEST(t.find({true, true, 100}) != t.end());
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
BOOST_TEST(t.find(testing2{true, true, 100}) != t.end());
std::set<testing2, Comparator > t2{
{true, true, 101},
{true, true, 100},
{true, false, 100},
{false, true, 100}
};
BOOST_TEST(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
BOOST_TEST(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
std::vector<testing> res;
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
std::back_inserter(res), Comparator{});
BOOST_TEST_EQ(res.size(), 4u);
}
void test_with_user_defined_constructor() {
struct pr {
int i;
short s;
pr() = default;
pr(const pr&) = default;
pr(pr&&) = default;
pr(int ii, short is) noexcept
: i(ii), s(is)
{}
};
pr p{1, 2};
//assert(flat_get<1>(p) == 2); // Compilation error
}
void test_hash() {
struct almost_pair { int i; short s; };
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
s.insert({0, 1});
s.insert({1, 0});
s.insert({1, 1});
BOOST_TEST_EQ(s.size(), 3u);
flat_hash<almost_pair> hs;
BOOST_TEST_NE(hs({0, 1}), hs({1, 0}));
BOOST_TEST_EQ(hs({0, 1}), hs({0, 1}));
BOOST_TEST_EQ(hs({1, 1}), hs({1, 1}));
BOOST_TEST_NE(hs({0, 0}), hs({1, 1}));
struct single_field { int i; };
BOOST_TEST_NE(flat_hash<single_field>()({1}), std::hash<int>()(1));
BOOST_TEST_NE(flat_hash<single_field>()({199}), std::hash<int>()(199));
}
// Test case by Lisa Lippincott
void test_alignment_with_nested_structure() {
struct A0 {
short s;
char c;
};
struct B0 {
A0 a;
char c1;
char c2;
};
B0 test_struct;
std::memset(&test_struct, 0, sizeof(test_struct));
test_struct.a.s = 0;
test_struct.a.c = '1';
test_struct.c1 = '2';
test_struct.c2 = '3';
BOOST_TEST_EQ(flat_get<0>(test_struct), 0);
BOOST_TEST_EQ(flat_get<1>(test_struct), '1');
BOOST_TEST_EQ(flat_get<2>(test_struct), '2');
BOOST_TEST_EQ(flat_get<3>(test_struct), '3');
}
template <std::size_t... I>
void test_and_debug_internals(std::index_sequence<I...>) {
struct A0 {
short s;
char c;
};
A0 a0 { 3, '4' };
BOOST_TEST_EQ(boost::pfr::flat_get<0>(a0), 3);
BOOST_TEST_EQ(boost::pfr::flat_get<1>(a0), '4');
struct A1 {
int i;
};
struct B1 {
A1 a;
int j;
};
B1 b1 { {5}, 6 };
BOOST_TEST_EQ(boost::pfr::flat_get<0>(b1), 5);
BOOST_TEST_EQ(boost::pfr::flat_get<1>(b1), 6);
/*
struct B0 {
A0 a;
char c1;
char c2;
};
typedef B0 type;
typedef B0 T;
using namespace boost::pfr::detail;
constexpr auto a = flat_array_of_type_ids<T>();
(void)a; // `a` is unused if T is an empty type
constexpr size_array<a.size()> skips_in_subtuples {{
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
}};
constexpr size_array<sizeof...(I) + 1> indexes_in_subtuples_uncleanuped {{ 1, 1 + I...}};
constexpr auto indexes_plus_1_and_zeros_as_skips = remove_skips(indexes_in_subtuples_uncleanuped, skips_in_subtuples);
constexpr auto new_size = size_t_<indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
constexpr auto indexes = resize_dropping_zeros_and_decrementing(new_size, indexes_plus_1_and_zeros_as_skips);
static_assert(indexes.data[0] == 0, "");
static_assert(indexes.data[1] == 4, "");
static_assert(indexes.data[2] == 5, "");
static_assert(
std::is_same<
decltype(boost::pfr::detail::as_flat_tuple_impl<type>(
detail::make_index_sequence< decltype(boost::pfr::detail::flat_array_of_type_ids<type>())::size() >()
)),
boost::pfr::detail::sequence_tuple::tuple<boost::pfr::detail::sequence_tuple::tuple<short, char>, char, char>
>::value,
""
);
constexpr auto res = as_flat_tuple_impl<foo>(
detail::make_index_sequence< decltype(flat_array_of_type_ids<foo>())::size() >()
);
auto afoo = flat_array_of_type_ids<foo>();
std::cerr << "\n\n";
for (std::size_t i = 0; i < afoo.size(); ++i) {
std::cerr << afoo.data[i] << ' ';
}
std::cerr << boost::typeindex::type_id<decltype(res)>() << "\n\n";*/
}
// test by Alexey Moiseytsev
void another_test_with_unusual_alignment() {
struct nested {
char c0;
char c1;
int i0;
short s0;
char c2;
};
struct pair {
nested n0;
nested n1;
};
// layout:
// offset struct tuple
// 0 n0.c0 n0.c0
// 1 n0.c1 n0.c1
// 2 padding padding
// 3 padding padding
// 4 n0.i0 n0.i0
// 5 n0.i0 n0.i0
// 6 n0.i0 n0.i0
// 7 n0.i0 n0.i0
// 8 n0.s0 n0.s0
// 9 n0.s0 n0.s0
// 10 n0.c2 n0.c2
// 11 padding n1.c0 !!!
// 12 n1.c0 n1.c1 !!!
// 13 n1.c1 padding !!!
// 14 padding padding
// 15 padding padding
// 16 n1.i0 n1.i0
// 17 n1.i0 n1.i0
// 18 n1.i0 n1.i0
// 19 n1.i0 n1.i0
// 20 n1.s0 n1.s0
// 21 n1.s0 n1.s0
// 22 n1.c2 n1.c2
// 23 padding padding
pair s{{'q', 'w', 12, 32, 'e'}, {'a', 's', 24, 64, 'd'}};
BOOST_TEST_EQ(flat_get<0>(s), 'q');
BOOST_TEST_EQ(flat_get<1>(s), 'w');
BOOST_TEST_EQ(flat_get<2>(s), 12);
BOOST_TEST_EQ(flat_get<3>(s), 32);
BOOST_TEST_EQ(flat_get<4>(s), 'e');
BOOST_TEST_EQ(flat_get<5>(s), 'a');
BOOST_TEST_EQ(flat_get<6>(s), 's');
BOOST_TEST_EQ(flat_get<7>(s), 24);
BOOST_TEST_EQ(flat_get<8>(s), 64);
BOOST_TEST_EQ(flat_get<9>(s), 'd');
}
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
// Test inspired by Anton Bikineev
void test_structure_with_default_values() {
struct test_me {
int i = 2;
short s = 14;
};
test_me s;
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
}
// Test inspired by Anton Bikineev
void test_st_layout_structure_with_non_constexpr_type() {
/* TODO: fixme
struct non_literal_structure {
int i1 = 3;
short s1 = 15;
non_literal_structure() = delete;
non_literal_structure(const non_literal_structure&) = delete;
non_literal_structure(non_literal_structure&&) = default;
non_literal_structure& operator=(const non_literal_structure&) = delete;
non_literal_structure& operator=(non_literal_structure&&) = delete;
};
struct test_me {
int i = 2;
short s = 14;
non_literal_structure nonlit{};
};
BOOST_TEST_EQ(tuple_size_v<test_me>, 3);
test_me s{};
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
BOOST_TEST_EQ(flat_get<2>(s), 3);
BOOST_TEST_EQ(flat_get<3>(s), 15);*/
}
// Test inspired by Anton Bikineev
void test_structure_with_user_provided_default_constructor() {
struct test_me {
short s = 2;
constexpr test_me(short){}
};
test_me s{0};
(void)s;
BOOST_TEST_EQ(flat_get<0>(s), 2); // TODO: fix compile time error message
}
#endif
/*
void test_copy_only_pod() {
struct copy_only_pod {
int i1;
short s1;
copy_only_pod() = delete;
copy_only_pod(copy_only_pod&&) = delete;
copy_only_pod(const copy_only_pod&) = default;
copy_only_pod& operator=(const copy_only_pod&) = delete;
copy_only_pod& operator=(copy_only_pod&&) = delete;
};
copy_only_pod s{2, 14};
BOOST_TEST_EQ(tuple_size_v<copy_only_pod>, 2u);
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
struct with_reference {
int& i;
int* p;
};
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
struct with_nested_copy_only_pod {
int i;
copy_only_pod p;
};
BOOST_TEST_EQ(tuple_size_v<with_nested_copy_only_pod>, 2u);
with_nested_copy_only_pod np{2, {3, 4}};
BOOST_TEST_EQ(flat_get<0>(np), 2);
BOOST_TEST_EQ(flat_get<1>(np), 3);
BOOST_TEST_EQ(flat_get<2>(np), 4);
} // */
/* // TODO: think of something with it!
void test_move_only_pod() {
struct move_only_pod {
int i1;
short s1;
move_only_pod() = delete;
//move_only_pod(move_only_pod&&) = delete;
move_only_pod(const move_only_pod&) = delete;
move_only_pod(move_only_pod&&) = default;
move_only_pod& operator=(const move_only_pod&) = delete;
move_only_pod& operator=(move_only_pod&&) = delete;
};
move_only_pod s{2, 14};
BOOST_TEST_EQ(tuple_size_v<move_only_pod>, 2u);
BOOST_TEST_EQ(flat_get<0>(s), 2);
BOOST_TEST_EQ(flat_get<1>(s), 14);
struct with_reference {
int& i;
int* p;
};
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
struct with_nested_move_only_pod {
int i;
short s;
move_only_pod p;
char c;
};
BOOST_TEST_EQ(tuple_size_v<with_nested_move_only_pod>, 4u);
// with_nested_move_only_pod np{2, {3, 4}};
// BOOST_TEST_EQ(flat_get<0>(np), 2);
// BOOST_TEST_EQ(flat_get<1>(np), 3);
// BOOST_TEST_EQ(flat_get<2>(np), 4);
} // */
int main() {
test_compiletime<foo>();
test_compiletime_array<int>();
test_compiletime_array<void*>();
test_compiletime_array<const void*>();
test_compiletime_array<char>();
test_compiletime_array<char const volatile*>();
{
foo f {
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
, {18, 19}
, {20, 21, {22, 23}}
};
test_runtime(f);
}
{
foo f {
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
, {-18, -19}
, {656565, 65535, {-22, -23}}
};
test_runtime(f);
}
test_with_enums();
test_comparable_struct();
test_empty_struct();
test_pods_with_int_operators();
test_struct_with_single_field();
test_with_contatiners<flat_less<>>();
test_with_contatiners<flat_greater<>>();
test_print();
test_with_user_defined_constructor();
test_hash();
struct non_pod1 {
std::string s;
std::vector<int> v;
int i;
struct foo {
std::string s2;
} f;
};
static_assert(tuple_size<non_pod1>::value == 4, "Must not be a compile error");
struct non_pod2 {
unsigned ui1: 1;
unsigned ui2: 2;
std::string s;
std::vector<int> v;
int i;
struct foo {
std::string s2;
} f;
};
static_assert(tuple_size<non_pod2>::value == 6, "Must not be a compile error even with bitfields");
int i_2dimens[2][2] = {{10, 11}, {12, 13} };
static_assert(tuple_size<decltype(i_2dimens)>::value == 4, "");
static_assert(flat_tuple_size<decltype(i_2dimens)>::value == 4, "");
test_and_debug_internals(detail::make_index_sequence<6>{});
test_alignment_with_nested_structure();
another_test_with_unusual_alignment();
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
test_structure_with_default_values();
test_st_layout_structure_with_non_constexpr_type();
test_structure_with_user_provided_default_constructor();
#endif
//test_copy_only_pod();
//test_move_only_pod();
return boost::report_errors();
}

View File

@@ -1,57 +0,0 @@
// Copyright (c) 2018 Adam Butcher, Antony Polukhin
// Copyright (c) 2019-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
struct point {
int x, y;
};
auto line(point a, point b) {
struct {
int timestamp;
point a, b;
} res = {123456, a, b};
return res;
}
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
int main() {
auto l = line({1, 2}, {3, 4});
int t, a, b, c, d;
using namespace boost::pfr;
using std::ignore;
flat_tie_from_structure (t, a, b, c, d) = l;
BOOST_TEST_EQ(t, 123456);
BOOST_TEST_EQ(a, 1);
BOOST_TEST_EQ(b, 2);
BOOST_TEST_EQ(c, 3);
BOOST_TEST_EQ(d, 4);
flat_tie_from_structure (ignore, ignore, a, b, c) = l;
BOOST_TEST_EQ(a, 2);
BOOST_TEST_EQ(b, 3);
BOOST_TEST_EQ(c, 4);
flat_tie_from_structure (ignore, a, b, c, ignore) = l;
BOOST_TEST_EQ(a, 1);
BOOST_TEST_EQ(b, 2);
BOOST_TEST_EQ(c, 3);
return boost::report_errors();
}
#else // C++14 without loophole
#include <iostream>
int main(int, char** argv) {
std::cerr << argv[0] << ": Not supported in C++14 without reflection loophole.\n";
}
#endif

View File

@@ -1,28 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
int main() {
struct nested { int i; short data[3]; };
struct foo { int i; nested n; };
std::size_t sum = 0;
boost::pfr::flat_for_each_field(foo{1, {2, {3, 4, 5}}}, [&sum](auto v) {
sum += v;
});
BOOST_TEST_EQ(sum, 15u);
sum = 0;
int array[] = {0, 1, 0, 2, 3, 0, 4, 5};
boost::pfr::flat_for_each_field(array, [&sum](auto v) {
sum += v;
});
BOOST_TEST_EQ(sum, 15u);
return boost::report_errors();
}

View File

@@ -1,12 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
int main() {
struct foo { int i; char c;};
static_assert(boost::pfr::flat_tuple_size_v<foo> == 2, "");
}

View File

@@ -1,23 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
struct bf {
unsigned int i1: 1;
unsigned int i2: 1;
unsigned int i3: 1;
unsigned int i4: 1;
unsigned int i5: 1;
unsigned int i6: 1;
};
int main() {
(void)boost::pfr::flat_tuple_size<bf>::value; // Must be a compile time error
return boost::report_errors();
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/flat/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <tuple>
int main() {
(void)boost::pfr::flat_tuple_size<std::pair<int, short>>::value; // Must be a compile time error
return boost::report_errors();
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Detection of type loophole.
// Inspired by the blog post: http://alexpolt.github.io/type-loophole.html
#include <type_traits>
#if defined(_MSC_VER) && _MSC_VER <= 1916
# error Compiler fails to do compile time computations for LoopHole. Fixed in later versions of the compiler
// Error: boost/pfr/detail/core14_loophole.hpp(98): error C3779: 'boost::pfr::detail::loophole': a function that returns 'auto' cannot be used before it is defined
#endif
template <unsigned> struct tag{};
template <class T, unsigned N>
struct loophole_t {
friend auto loophole(tag<N>) { return T{}; };
};
auto loophole(tag<0>);
int main() {
sizeof(loophole_t<unsigned, 0>);
static_assert( std::is_same<unsigned, decltype( loophole(tag<0>{}) ) >::value, "");
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// requires: C++14
#include <iostream>
#include "boost/pfr/precise.hpp"
struct my_struct { // no ostream operator defined!
int i;
char c;
double d;
};
int main() {
using namespace boost::pfr::ops; // out-of-the-box ostream operator for all PODs!
my_struct s{100, 'H', 3.141593};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include "boost/pfr/precise.hpp"
struct my_struct { // no ostream operator defined!
std::string s;
int i;
};
int main() {
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
using namespace boost::pfr::ops; // C++17 out-of-the-box ostream operators for aggregate initializables!
my_struct s{{"Das ist fantastisch!"}, 100};
std::cout << "my_struct has " << boost::pfr::tuple_size<my_struct>::value
<< " fields: " << s << "\n";
#endif
}

35
test/print_config.cpp Normal file
View File

@@ -0,0 +1,35 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/core.hpp>
#include <iostream>
int main() {
std::cout << "Platform info:" << '\n'
<< "BOOST_PFR_USE_CPP17 == " << BOOST_PFR_USE_CPP17 << '\n'
<< "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n'
<< "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n'
<< "__cplusplus == " << __cplusplus << '\n'
#ifdef __cpp_structured_bindings
<< "__cpp_structured_bindings == " << __cpp_structured_bindings << '\n'
#endif
#ifdef _MSC_VER
<< "_MSC_VER == " << _MSC_VER << '\n'
#endif
#ifdef _MSVC_LANG
<< "_MSVC_LANG == " << _MSVC_LANG << '\n'
#endif
#ifdef __GLIBCXX__
<< "__GLIBCXX__ == " << __GLIBCXX__ << '\n'
#endif
#ifdef __GNUC__
<< "__GNUC__ == " << __GNUC__ << '\n'
#endif
#ifdef __clang_major__
<< "__clang_major__ == " << __clang_major__ << '\n'
#endif
;
}

View File

@@ -3,8 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/pfr/tuple_size.hpp>
struct bf {
unsigned int i1: 1;
@@ -16,8 +15,7 @@ struct bf {
};
int main() {
(void)boost::pfr::tuple_size<bf>::value;
return boost::report_errors();
static_assert(boost::pfr::tuple_size<bf>::value == 6, "");
}

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/ops.hpp>
#include <boost/pfr/io.hpp>
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <sstream>
#include <set>
#include <string>
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#ifdef __clang__
# pragma clang diagnostic ignored "-Wmissing-braces"
#endif
union test_union {
int i;
float f;
};
constexpr bool operator< (test_union l, test_union r) noexcept { return l.i < r.i; }
constexpr bool operator<=(test_union l, test_union r) noexcept { return l.i <= r.i; }
constexpr bool operator> (test_union l, test_union r) noexcept { return l.i > r.i; }
constexpr bool operator>=(test_union l, test_union r) noexcept { return l.i >= r.i; }
constexpr bool operator==(test_union l, test_union r) noexcept { return l.i == r.i; }
constexpr bool operator!=(test_union l, test_union r) noexcept { return l.i != r.i; }
template <class T>
void test_constexpr_comparable() {
using namespace boost::pfr;
constexpr T s1 {110, 1, true, 6,17,8,9,10,11};
constexpr T s2 = s1;
constexpr T s3 {110, 1, true, 6,17,8,9,10,11111};
static_assert(eq(s1, s2), "");
static_assert(le(s1, s2), "");
static_assert(ge(s1, s2), "");
static_assert(!ne(s1, s2), "");
static_assert(!eq(s1, s3), "");
static_assert(ne(s1, s3), "");
static_assert(lt(s1, s3), "");
static_assert(gt(s3, s2), "");
static_assert(le(s1, s3), "");
static_assert(ge(s3, s2), "");
}
namespace foo {
struct comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
}
int main() {
// MSVC fails to use strucutred bindings in constexpr:
//
// error C2131: expression did not evaluate to a constant
// pfr/detail/functional.hpp(21): note: failure was caused by a read of a variable outside its lifetime
#if !defined(_MSC_VER) || (_MSC_VER >= 1927) || !BOOST_PFR_USE_CPP17
test_constexpr_comparable<foo::comparable_struct>();
struct local_comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
test_constexpr_comparable<local_comparable_struct>();
struct local_comparable_struct_with_union {
int i; short s; bool bl; int a,b,c,d,e; test_union u;
};
test_constexpr_comparable<local_comparable_struct>();
#endif
return boost::report_errors();
}

View File

@@ -4,11 +4,9 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/core.hpp>
#include <boost/core/lightweight_test.hpp>
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
auto parseHex(char const* p, size_t limit = ~0u) {
struct { size_t val; char const* rest; } res = { 0, p };
while (limit) {
@@ -60,12 +58,3 @@ int main() {
return boost::report_errors();
}
#else // C++14 without loophole
#include <iostream>
int main(int, char** argv) {
std::cerr << argv[0] << ": Not supported in C++14 without reflection loophole.\n";
}
#endif

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
// boost::pfr::for_each_field crashes when sizeof(MyConfig) > 248 (probably >= 256)
#include <boost/pfr/precise.hpp>
#include <boost/pfr.hpp>
#include <iostream>
#include <type_traits>

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -3,7 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <sstream>

View File

@@ -3,15 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
# include <boost/pfr/flat/functions_for.hpp>
# define BOOST_PFR_TEST_FUNCTIONS_FOR BOOST_PFR_FLAT_FUNCTIONS_FOR
#elif defined(BOOST_PFR_TEST_PRECISE)
# include <boost/pfr/precise/functions_for.hpp>
# define BOOST_PFR_TEST_FUNCTIONS_FOR BOOST_PFR_PRECISE_FUNCTIONS_FOR
#else
# error Misused test
#endif
#include <boost/pfr/functions_for.hpp>
#include <boost/core/lightweight_test.hpp>
@@ -37,7 +29,7 @@ struct comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(comparable_struct)
BOOST_PFR_FUNCTIONS_FOR(comparable_struct)
template <typename Struct>
void test_some_comparable_struct() {
@@ -73,7 +65,7 @@ void test_comparable_struct() {
}
struct empty { operator std::string() { return "empty{}"; } };
BOOST_PFR_TEST_FUNCTIONS_FOR(empty)
BOOST_PFR_FUNCTIONS_FOR(empty)
void test_empty_struct() {
BOOST_TEST_EQ(empty{}, empty{});
@@ -81,7 +73,7 @@ void test_empty_struct() {
namespace foo {
struct testing { bool b1, b2; int i; };
BOOST_PFR_TEST_FUNCTIONS_FOR(testing);
BOOST_PFR_FUNCTIONS_FOR(testing);
}
template <class Comparator>
@@ -107,7 +99,7 @@ void test_implicit_conversions() {
ss.str("");
ss << empty{};
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_TEST_FUNCTIONS_FOR
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_FUNCTIONS_FOR
}
namespace {
@@ -116,14 +108,14 @@ struct anonymous_comparable_struct {
int i; short s; bool bl; int a,b,c,d,e,f;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(anonymous_comparable_struct)
BOOST_PFR_FUNCTIONS_FOR(anonymous_comparable_struct)
struct other_anonymous_struct {
anonymous_comparable_struct a,b;
};
BOOST_PFR_TEST_FUNCTIONS_FOR(other_anonymous_struct)
BOOST_PFR_FUNCTIONS_FOR(other_anonymous_struct)
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/core.hpp>
#include <boost/type_index.hpp>
#include <boost/core/lightweight_test.hpp>
namespace testing {
namespace {
struct other_anon {
int data;
};
struct anon {
other_anon a;
const other_anon b;
};
void test_get_in_anon_ns_const_field() {
anon x{{1}, {2}};
BOOST_TEST_EQ(boost::pfr::get<0>(x).data, 1);
auto x0_type = boost::typeindex::type_id_with_cvr<decltype(
boost::pfr::get<0>(x)
)>();
// Use runtime check to make sure that Loophole fails to compile structure_tie
BOOST_TEST_EQ(x0_type, boost::typeindex::type_id_with_cvr<other_anon&>());
BOOST_TEST_EQ(boost::pfr::get<1>(x).data, 2);
auto x1_type = boost::typeindex::type_id_with_cvr<decltype(
boost::pfr::get<1>(x)
)>();
// Use runtime check to make sure that Loophole fails to compile structure_tie
BOOST_TEST_EQ(x1_type, boost::typeindex::type_id_with_cvr<const other_anon&>());
}
} // anonymous namespace
} // namespace testing
int main() {
testing::test_get_in_anon_ns_const_field();
return boost::report_errors();
}

View File

@@ -3,7 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise.hpp>
#include <boost/pfr.hpp>
#include <boost/core/lightweight_test.hpp>
template <class T>
@@ -19,11 +19,9 @@ struct Foo {
};
int main() {
#if BOOST_PFR_USE_LOOPHOLE || BOOST_PFR_USE_CPP17
Foo f{0};
f.a.val_ = 5;
BOOST_TEST_EQ(boost::pfr::get<0>(f).val_, 5);
return boost::report_errors();
#endif
}

31
test/run/get_rvalue.cpp Normal file
View File

@@ -0,0 +1,31 @@
// Copyright (c) 2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/core.hpp>
#include <memory>
#include <boost/core/lightweight_test.hpp>
struct unique_ptrs {
std::unique_ptr<int> p1;
std::unique_ptr<int> p2;
};
void test_get_rvalue() {
unique_ptrs x {
std::make_unique<int>(42),
std::make_unique<int>(43),
};
auto p = boost::pfr::get<0>(std::move(x));
BOOST_TEST_EQ(*p, 42);
}
int main() {
test_get_rvalue();
return boost::report_errors();
}

View File

@@ -14,9 +14,9 @@ struct my_struct { // no ostream operator defined!
};
int main() {
using namespace boost::pfr::flat_ops; // ostream operator out-of-the-box for all PODs!
my_struct s{100, 'H', 3.141593};
std::cout << "my_struct has " << boost::pfr::flat_tuple_size<my_struct>::value
<< " fields: " << s << "\n";
std::cout << "my_struct has "
<< boost::pfr::tuple_size<my_struct>::value // Outputs: 3
<< " fields: "
<< boost::pfr::io(s); // Outputs: {100, 'H', 3.141593}
}

View File

@@ -12,11 +12,10 @@ struct my_struct { // no ostream operator defined!
};
int main() {
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
using namespace boost::pfr::flat_ops; // C++17 out-of-the-box ostream operators for aggregate initializables!
my_struct s{{"Das ist fantastisch!"}, 100};
std::cout << "my_struct has " << boost::pfr::flat_tuple_size<my_struct>::value
<< " fields: " << s << "\n";
#endif
std::cout << "my_struct has "
<< boost::pfr::tuple_size<my_struct>::value // Outputs: 2
<< " fields: "
<< boost::pfr::io(s); // Outputs: {"Das ist fantastisch!", 100};
}

View File

@@ -1,15 +1,9 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_PRECISE
# include <boost/pfr/precise/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_FLAT)
# include <boost/pfr/flat/tuple_size.hpp>
#else
# error Misused test
#endif
#include <boost/pfr/tuple_size.hpp>
#include <boost/core/lightweight_test.hpp>
@@ -24,7 +18,6 @@ struct X {
struct S { X x0; X x1; int x2; X x3; };
int main() {
#ifdef BOOST_PFR_TEST_PRECISE
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
struct S5_0 { int x0; int x1; int x2; int x3; X x4; };
@@ -44,11 +37,6 @@ int main() {
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
#elif defined(BOOST_PFR_TEST_FLAT)
// Test disabled in Jamfile!
// Does not compile since GCC-10. Result is quite strange on compilers where the code compiles:
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
#endif
return boost::report_errors();
}

View File

@@ -3,18 +3,11 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_PRECISE
# include <boost/pfr/precise/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_FLAT)
# include <boost/pfr/flat/tuple_size.hpp>
#else
# error Misused test
#endif
#include <boost/pfr/tuple_size.hpp>
#include <type_traits>
#include <boost/core/lightweight_test.hpp>
struct X {
X(X&&) = default;
X(const X&) = delete;
@@ -28,7 +21,6 @@ static_assert(!std::is_default_constructible<X>::value, "");
static_assert(!std::is_default_constructible<S>::value, "");
int main() {
#ifdef BOOST_PFR_TEST_PRECISE
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
struct S5_0 { int x0; int x1; int x2; int x3; X x4; };
@@ -48,12 +40,5 @@ int main() {
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
#elif defined(BOOST_PFR_TEST_FLAT)
// Test disabled in Jamfile!
// Does not compile since GCC-10. Result is quite strange on compilers where the code compiles:
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
#endif
return boost::report_errors();
}

View File

@@ -1,15 +1,9 @@
// Copyright (c) 2018 Antony Polukhin
// Copyright (c) 2018-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_PRECISE
# include <boost/pfr/precise/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_FLAT)
# include <boost/pfr/flat/tuple_size.hpp>
#else
# error Misused test
#endif
#include <boost/pfr/tuple_size.hpp>
struct X {
X(int) {}
@@ -17,7 +11,6 @@ struct X {
struct S { X x0; X x1; int x2; X x3; };
int main() {
#ifdef BOOST_PFR_TEST_PRECISE
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
struct S5_0 { int x0; int x1; int x2; int x3; X x4; };
@@ -37,8 +30,5 @@ int main() {
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
#elif defined(BOOST_PFR_TEST_FLAT)
return boost::pfr::flat_tuple_size_v<S>;
#endif
}

View File

@@ -3,13 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
# include <boost/pfr/flat/tuple_size.hpp>
#elif defined(BOOST_PFR_TEST_PRECISE)
# include <boost/pfr/precise/tuple_size.hpp>
#else
# error Misused test
#endif
#include <boost/pfr/tuple_size.hpp>
struct non_standard_layout_member {
@@ -27,10 +21,6 @@ struct test_with_non_st_layout {
};
int main() {
#ifdef BOOST_PFR_TEST_FLAT
return boost::pfr::flat_tuple_size<test_with_non_st_layout>::value;
#else
static_assert(boost::pfr::tuple_size<test_with_non_st_layout>::value == 3, "");
#endif
}

View File

@@ -3,7 +3,8 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <boost/pfr/ops.hpp>
#include <boost/pfr/io.hpp>
#include <iostream>
#include <typeinfo>
@@ -12,15 +13,10 @@
#include <set>
#include <string>
#include <boost/core/lightweight_test.hpp>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/ops.hpp>
#define BOOST_PFR_TEST_NAMESPECE boost::pfr::flat_ops
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/ops.hpp>
#define BOOST_PFR_TEST_NAMESPECE boost::pfr::ops
#ifdef __clang__
# pragma clang diagnostic ignored "-Wmissing-braces"
#endif
unsigned test_union_counter = 0;
@@ -42,45 +38,41 @@ inline std::istream& operator>>(std::istream& is, test_union& src) { ++test_unio
template <class T>
void test_comparable_struct() {
using namespace BOOST_PFR_TEST_NAMESPECE;
using namespace boost::pfr;
T s1 {0, 1, false, 6,7,8,9,10,11};
T s2 = s1;
T s3 {0, 1, false, 6,7,8,9,10,11111};
BOOST_TEST(s1 == s2);
BOOST_TEST(s1 <= s2);
BOOST_TEST(s1 >= s2);
BOOST_TEST(!(s1 != s2));
BOOST_TEST(!(s1 == s3));
BOOST_TEST(s1 != s3);
BOOST_TEST(s1 < s3);
BOOST_TEST(s3 > s2);
BOOST_TEST(s1 <= s3);
BOOST_TEST(s3 >= s2);
BOOST_TEST(eq(s1, s2));
BOOST_TEST(le(s1, s2));
BOOST_TEST(ge(s1, s2));
BOOST_TEST(!ne(s1, s2));
BOOST_TEST(!eq(s1, s3));
BOOST_TEST(ne(s1, s3));
BOOST_TEST(lt(s1, s3));
BOOST_TEST(gt(s3, s2));
BOOST_TEST(le(s1, s3));
BOOST_TEST(ge(s3, s2));
std::cout << s1 << std::endl;
std::cout << boost::pfr::io(s1);
T s4;
std::stringstream ss;
ss.exceptions ( std::ios::failbit);
ss << s1;
ss >> s4;
std::cout << s4 << std::endl;
BOOST_TEST(s1 == s4);
int i = 1, j = 2;
BOOST_TEST_NE(i, j);
ss << boost::pfr::io(s1);
ss >> boost::pfr::io(s4);
std::cout << boost::pfr::io(s4);
BOOST_TEST(eq(s1, s4));
}
void test_empty_struct() {
struct empty {};
using namespace BOOST_PFR_TEST_NAMESPECE;
std::cout << empty{};
BOOST_TEST(empty{} == empty{});
std::cout << boost::pfr::io(empty{});
BOOST_TEST(boost::pfr::eq(empty{}, empty{}));
}
void test_implicit_conversions() {
using namespace BOOST_PFR_TEST_NAMESPECE;
std::stringstream ss;
ss << std::true_type{};
ss << boost::pfr::io(std::true_type{});
BOOST_TEST_EQ(ss.str(), "1"); // Does not break implicit conversion
}
@@ -99,7 +91,6 @@ int main() {
};
test_comparable_struct<local_comparable_struct>();
#if defined(BOOST_PFR_TEST_PRECISE)
struct local_comparable_struct_with_union {
int i; short s; bool bl; int a,b,c,d,e; test_union u;
};
@@ -107,7 +98,6 @@ int main() {
// Making sure that test_union overloaded operations were called.
BOOST_TEST_EQ(test_union_counter, 17);
#endif
test_empty_struct();
test_implicit_conversions();

View File

@@ -0,0 +1,78 @@
// Copyright (c) 2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <boost/pfr/core.hpp>
#include <chrono>
#include <optional>
// This class mimics libc++ implementation of std::chrono::duration with unfxed LWG3050
template <class Rep, class Period>
class bogus_duration {
public:
bogus_duration() = default;
template <class T>
explicit bogus_duration(const T& val,
typename std::enable_if<
std::is_convertible<T, Rep>::value // <= libstdc++ fix for LWG3050 is 's/T/const T&/g'
>::type* = nullptr)
: rep_(val)
{}
template <class Rep2, class Period2>
bogus_duration(const bogus_duration<Rep2, Period2>& val,
typename std::enable_if<std::is_convertible<Period2, Rep>::value>::type* = nullptr)
: rep_(val)
{}
Rep get_rep() const { return rep_; }
private:
Rep rep_{0};
};
struct struct_with_bogus_duration {
std::optional<bogus_duration<long, char>> d0;
std::optional<bogus_duration<long, char>> d1;
};
struct struct_with_optional {
std::optional<std::chrono::seconds> a;
std::optional<std::chrono::milliseconds> b;
std::optional<std::chrono::microseconds> c;
std::optional<std::chrono::nanoseconds> d;
std::optional<std::chrono::steady_clock::duration> e;
std::optional<std::chrono::system_clock::duration> f;
};
int main() {
struct_with_optional val{
std::chrono::seconds{1},
std::chrono::seconds{2},
std::chrono::seconds{3},
std::chrono::seconds{4},
std::chrono::seconds{5},
std::chrono::seconds{6},
};
using boost::pfr::get;
BOOST_TEST(get<0>(val) == std::chrono::seconds{1});
BOOST_TEST(get<1>(val) == std::chrono::seconds{2});
BOOST_TEST(get<2>(val) == std::chrono::seconds{3});
BOOST_TEST(get<3>(val) == std::chrono::seconds{4});
BOOST_TEST(get<3>(val) > std::chrono::seconds{0});
BOOST_TEST(get<3>(val) > std::chrono::seconds{0});
struct_with_bogus_duration val2{bogus_duration<long, char>{1}, bogus_duration<long, char>{2}};
BOOST_TEST(get<0>(val2)->get_rep() == 1);
BOOST_TEST(get<1>(val2)->get_rep() == 2);
return boost::report_errors();
}

View File

@@ -3,7 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/precise.hpp>
#include <boost/pfr.hpp>
#include <boost/core/lightweight_test.hpp>
template <class T>
@@ -19,11 +19,9 @@ struct Foo {
};
int main() {
#if BOOST_PFR_USE_LOOPHOLE || BOOST_PFR_USE_CPP17
Foo f{0};
f.a.val_ = 5;
BOOST_TEST_EQ(boost::pfr::get<0>(f).val_, 5);
return boost::report_errors();
#endif
}

View File

@@ -3,45 +3,19 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/core/lightweight_test.hpp>
#include <boost/pfr/io.hpp>
#include <sstream>
#include <string>
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/io.hpp>
namespace boost { namespace test {
template <class Char, class Traits, class T>
void read(std::basic_istream<Char, Traits>& in, T& value) {
::boost::pfr::flat_read(in, value);
}
template <class Char, class Traits, class T>
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
::boost::pfr::flat_write(out, value);
}
}}
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/io.hpp>
namespace boost { namespace test {
using boost::pfr::read;
using boost::pfr::write;
}}
#endif
#include <boost/core/lightweight_test.hpp>
template <class T>
void test_write_read(const T& value) {
T result;
std::stringstream ss;
boost::test::write(ss, value);
boost::test::read(ss, result);
ss << boost::pfr::io(value);
ss >> boost::pfr::io(result);
BOOST_TEST_EQ(value.f0, result.f0);
BOOST_TEST_EQ(value.f1, result.f1);
BOOST_TEST_EQ(value.f2, result.f2);
@@ -52,7 +26,7 @@ void test_write_read(const T& value) {
template <class T>
void to_string_test(const T& value, const char* ethalon) {
std::stringstream ss;
boost::test::write(ss, value);
ss << boost::pfr::io(value);
BOOST_TEST_EQ(ss.str(), ethalon);
}
@@ -88,7 +62,6 @@ int main() {
test_type(test1{1, 2, '3', 4, 5}, "{1, 2, 3, 4, 5}");
test_type(test1{199, 299, '9', 499, 599}, "{199, 299, 9, 499, 599}");
#ifdef BOOST_PFR_TEST_PRECISE
struct test2 {
with_operator f0;
with_operator f1;
@@ -111,39 +84,6 @@ int main() {
"{1, 2, 3, 4, {with_operator}}"
);
#if (BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE) \
&& !defined(_MSC_VER) /* TODO: remove after fixing strange errors https://ci.appveyor.com/project/apolukhin/magic-get/build/1.65.108-develop */
struct test4 {
int f0;
std::string f1;
char f2;
int f3;
std::string f4;
};
test_type(
test4{1, {"my o my"}, '3', 4, {"hello there!"} },
"{1, \"my o my\", 3, 4, \"hello there!\"}"
);
#if 0
// TODO:
std::string f1_referenced{"my O my"};
std::string f4_referenced{"Hello There!"};
struct test5 {
int f0;
const std::string& f1;
char f2;
int f3;
const std::string& f4;
};
to_string_test(
test5{1, f1_referenced, '3', 4, f4_referenced },
"{1, \"my o my\", 3, 4, \"hello there!\"}"
);
#endif
#endif
#endif // BOOST_PFR_TEST_PRECISE
return boost::report_errors();
}

View File

@@ -0,0 +1,75 @@
// Copyright (c) 2016-2020 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/io.hpp>
#include <sstream>
#include <string>
#include <boost/core/lightweight_test.hpp>
template <class T>
void test_write_read(const T& value) {
T result;
std::stringstream ss;
ss << boost::pfr::io(value);
ss >> boost::pfr::io(result);
BOOST_TEST_EQ(value.f0, result.f0);
BOOST_TEST_EQ(value.f1, result.f1);
BOOST_TEST_EQ(value.f2, result.f2);
BOOST_TEST_EQ(value.f3, result.f3);
BOOST_TEST_EQ(value.f4, result.f4);
}
template <class T>
void to_string_test(const T& value, const char* ethalon) {
std::stringstream ss;
ss << boost::pfr::io(value);
BOOST_TEST_EQ(ss.str(), ethalon);
}
template <class T>
void test_type(const T& value, const char* ethalon) {
test_write_read(value);
to_string_test(value, ethalon);
}
int main() {
#if !defined(_MSC_VER) /* TODO: remove after fixing strange errors https://ci.appveyor.com/project/apolukhin/magic-get/build/1.65.108-develop */
struct test4 {
int f0;
std::string f1;
char f2;
int f3;
std::string f4;
};
test_type(
test4{1, {"my o my"}, '3', 4, {"hello there!"} },
"{1, \"my o my\", 3, 4, \"hello there!\"}"
);
#if 0
// TODO:
std::string f1_referenced{"my O my"};
std::string f4_referenced{"Hello There!"};
struct test5 {
int f0;
const std::string& f1;
char f2;
int f3;
const std::string& f4;
};
to_string_test(
test5{1, f1_referenced, '3', 4, f4_referenced },
"{1, \"my o my\", 3, 4, \"hello there!\"}"
);
#endif
#endif
return boost::report_errors();
}

Some files were not shown because too many files have changed in this diff Show More