mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-22 05:22:32 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50d58a2e84 | ||
|
|
76ac44a9ca | ||
|
|
4205a2e553 | ||
|
|
89b1d45ff7 | ||
|
|
26867f47b7 | ||
|
|
b9166fd38e | ||
|
|
915bd9217c | ||
|
|
0885412a7d | ||
|
|
86ebac6e0c | ||
|
|
39e9b4c5fe | ||
|
|
01fd8db5b4 | ||
|
|
077ea5451c | ||
|
|
3a36467d96 | ||
|
|
3eee880972 | ||
|
|
41a22fcd21 | ||
|
|
e354ba8b25 | ||
|
|
7a0f5f90df | ||
|
|
041b0dd226 | ||
|
|
ff1c5e3a7f | ||
|
|
4c48a220c2 | ||
|
|
ed6fe1431d | ||
|
|
16db439e8c | ||
|
|
c3ccb7a525 | ||
|
|
d6e44dde8f | ||
|
|
63b5f1f791 | ||
|
|
dc814c7e7f | ||
|
|
671cc3f282 | ||
|
|
8ca6b531a6 | ||
|
|
f24698f131 | ||
|
|
950e4aa0ee | ||
|
|
b9bea47e4f | ||
|
|
6d1fc03667 | ||
|
|
ba65dd23ef | ||
|
|
5b28535b8e | ||
|
|
802c7033ba | ||
|
|
4a593c0628 | ||
|
|
b603f6fdef | ||
|
|
1a620d36dd | ||
|
|
93cb89cf05 | ||
|
|
d2964544a4 |
64
.travis.yml
64
.travis.yml
@@ -2,7 +2,7 @@
|
||||
# subject to 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)
|
||||
#
|
||||
# Copyright Antony Polukhin 2014-2019.
|
||||
# Copyright Antony Polukhin 2014-2020.
|
||||
|
||||
#
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
@@ -10,30 +10,9 @@
|
||||
#
|
||||
# File revision #9 (with DIFF)
|
||||
|
||||
sudo: false
|
||||
language: cpp
|
||||
os: linux
|
||||
|
||||
env:
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BOOST_BRANCH=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# 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
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
|
||||
# This will force to use local repo content, instead of the Boost's default.
|
||||
- BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
|
||||
|
||||
# Global options for sanitizers
|
||||
- UBSAN_OPTIONS=print_stacktrace=1
|
||||
- LSAN_OPTIONS=verbosity=1:log_threads=1
|
||||
dist: bionic
|
||||
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
matrix:
|
||||
@@ -45,6 +24,14 @@ matrix:
|
||||
# sources: ubuntu-toolchain-r-test
|
||||
# packages: g++-6
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-10 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
|
||||
name: "GCC-10"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages: g++-10
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
|
||||
name: "GCC-8"
|
||||
sudo: required # Required by leak sanitizer
|
||||
@@ -76,16 +63,16 @@ matrix:
|
||||
sources: llvm-toolchain-trusty-6
|
||||
packages: clang-6.0
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,1z toolset=clang-8 cxxflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined"'
|
||||
name: "Clang-8, libc++"
|
||||
- env: B2_ARGS='cxxstd=14,17,20 toolset=clang-10 cxxflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined"'
|
||||
name: "Clang-10, libc++"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: llvm-toolchain-trusty-8
|
||||
sources: llvm-toolchain-bionic-10
|
||||
packages:
|
||||
- clang-8
|
||||
- libc++-8-dev
|
||||
- libc++abi-8-dev
|
||||
- clang-10
|
||||
- libc++-10-dev
|
||||
- libc++abi-10-dev
|
||||
|
||||
# Sanitizers disabled for this toolset as they started causing link troubles:
|
||||
# hidden symbol `_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE11__recommendEm' isn't defined
|
||||
@@ -108,6 +95,24 @@ addons:
|
||||
- python-yaml
|
||||
|
||||
before_install:
|
||||
# Autodetect Boost branch by using the following code: - BOOST_BRANCH=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# 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
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
|
||||
# This will force to use local repo content, instead of the Boost's default.
|
||||
- BOOST_REMOVE=$(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`
|
||||
|
||||
@@ -138,6 +143,7 @@ before_install:
|
||||
echo "using clang : 6 : clang++-6.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 7 : clang++-7.0 ;" >> ~/user-config.jam
|
||||
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/
|
||||
|
||||
|
||||
259
doc/pfr.qbk
259
doc/pfr.qbk
@@ -1,4 +1,4 @@
|
||||
[library Boost.Precise and Flat Reflection
|
||||
[library Boost.PFR
|
||||
[quickbook 1.6]
|
||||
[version 1.0]
|
||||
[copyright 2016-2020 Antony Polukhin]
|
||||
@@ -17,7 +17,7 @@ In C++ we have:
|
||||
* 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.
|
||||
|
||||
This library provides tuple like methods for aggregate initializable structures, making them usable in contexts were only tuples were useful.
|
||||
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>`.
|
||||
|
||||
@@ -47,25 +47,130 @@ Boost.Precise and Flat Reflection (Boost.PFR) adds following out-of-the-box func
|
||||
* 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.
|
||||
|
||||
[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 This is a C++14 library! Pre C++14 compilers (C++11, C++03...) are not supported]
|
||||
[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]
|
||||
|
||||
[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: ]]
|
||||
[
|
||||
[ [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_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] ]
|
||||
][
|
||||
[ [pfr_quick_examples_for_each] ]
|
||||
[ `var == {B, {787, 103.142}}` ]
|
||||
[ [funcref boost::pfr::for_each_field for_each_field] ]
|
||||
][
|
||||
[ [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_for_each_idx] ]
|
||||
[ ```0: char
|
||||
1: quick_examples_ns::foo
|
||||
``` ]
|
||||
[ [funcref boost::pfr::for_each_field 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] ]
|
||||
][
|
||||
[ [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] ]
|
||||
][
|
||||
[ [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] ]
|
||||
]]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Tutorial]
|
||||
|
||||
[section Accessing POD member by index] [pfr_example_get] [endsect]
|
||||
[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] ]
|
||||
|
||||
[section Flat or Precise functions to choose]
|
||||
All the functions that have `flat_` prefix and are declared in `boost/pfr/flat/*` headers 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.
|
||||
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.
|
||||
|
||||
* If you wish types flattened - use [*flat] functions
|
||||
* If you use types with C arrays - use [*flat] functions
|
||||
* Otherwise use [*precise] functions
|
||||
Use [*flat] functions if you:
|
||||
|
||||
* wish types flattened
|
||||
* or you reflect types with C arrays
|
||||
|
||||
For all the other cases prefer [*precise] functions.
|
||||
|
||||
[warning MSVC currently supports only [*precise] functions and only in /std:c++latest or /std:c++17 modes.]
|
||||
|
||||
@@ -78,7 +183,7 @@ There are three ways to start using Boost.PFR hashing, comparison and streaming
|
||||
|
||||
[table:flat_ops_comp Different approaches for operators
|
||||
[[ Approach
|
||||
][ Defines operators in global namespace ][ Defined operators could be found by ADL ][ Works for local types ][ Usable localy, without affecting code from other scopes ][ Ignores implicit conversion operators ][ Respects user defined operators ]]
|
||||
][ 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 ]]
|
||||
|
||||
[[
|
||||
[headerref boost/pfr/precise/ops.hpp using\u00A0namespace\u00A0boost::pfr::ops;]
|
||||
@@ -138,7 +243,7 @@ struct uniform_comparator_less {
|
||||
|
||||
[*2. [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR] and [macroref BOOST_PFR_PRECISE_FUNCTIONS_FOR] approach]
|
||||
|
||||
This method is good if you're writing POD structure and wish to define operators for that structure.
|
||||
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>
|
||||
|
||||
@@ -186,7 +291,7 @@ struct pair_like {
|
||||
assert(pair_like{1, 2} < pair_like{1, 3});
|
||||
```
|
||||
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 all POD types won't be used during comparisons/streaming/hashing.*
|
||||
*All conversion operators of types are not used during comparisons/streaming/hashing.*
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -229,104 +334,6 @@ error: static_assert failed "====================> Boost.PFR: For safety reasons
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Short Examples for the Impatient]
|
||||
|
||||
[import ../example/quick_examples.cpp]
|
||||
|
||||
[pfr_quick_examples_structures]
|
||||
|
||||
Following examples use definition from above:
|
||||
|
||||
[table:quick_examples
|
||||
[[ Code snippet ] [ `var` content or output ] [ Function description: ]]
|
||||
[
|
||||
[ [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_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] ]
|
||||
][
|
||||
[ [pfr_quick_examples_for_each] ]
|
||||
[ `var == {B, {787, 103.142}}` ]
|
||||
[ [funcref boost::pfr::for_each_field for_each_field] ]
|
||||
][
|
||||
[ [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_for_each_idx] ]
|
||||
[ ```0: char
|
||||
1: quick_examples_ns::foo
|
||||
``` ]
|
||||
[ [funcref boost::pfr::for_each_field 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] ]
|
||||
][
|
||||
[ [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_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] ]
|
||||
][
|
||||
[ [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] ]
|
||||
]]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section 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:
|
||||
@@ -334,36 +341,30 @@ By default Boost.PFR [*auto-detects your compiler abilities] and automatically d
|
||||
[[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. ]]
|
||||
]
|
||||
|
||||
Note that disabling [*Loophole] in C++14 significantly limitates the reflection abilities of the library. See next section for more info.
|
||||
Note that disabling [*Loophole] in C++14 significantly limits the reflection abilities of the library. See next section for more info.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Requirements and Limitations]
|
||||
[section Limitations]
|
||||
|
||||
[note Boost.PFR does not depend on any Boost library. You may use it's headers even without Boost. ]
|
||||
The reflection has some limitations that depend on a C++ Standard and compiler capabilities:
|
||||
|
||||
* Boost.PFR *requires C++14 compatible compiler* (GCC-5.0+, Clang, ...)
|
||||
* Static variables are ignored
|
||||
* T must be aggregate initializable
|
||||
|
||||
[*Flat] functions limitations:
|
||||
|
||||
* T must be POD and must not contain references nor bitfields
|
||||
* Enums will be returned as their underlying type
|
||||
|
||||
C++14 [*precise] functions limitations with manually disabled [*Loophole](C++17 or not disabling Loophole fixes those):
|
||||
|
||||
* 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
|
||||
|
||||
|
||||
[*C++14] limitation (C++17 fixes those):
|
||||
|
||||
* Non of the member fields has a template constructor from one parameter
|
||||
* Additional C++14 [*only] limitations (switch to C++17 to remove all of those):
|
||||
* 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
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -373,7 +374,7 @@ 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 remeber types it has been converted to during aggregate initialization of 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
|
||||
|
||||
@@ -147,7 +147,7 @@ void test_examples() {
|
||||
{
|
||||
bar var{'A', {777, 3.141593}};
|
||||
//[pfr_quick_examples_get_1
|
||||
boost::pfr::get<1>(var) = foo{1, 2}; // C++17 is required
|
||||
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';
|
||||
}
|
||||
@@ -182,7 +182,7 @@ void test_examples() {
|
||||
{
|
||||
bar var{'A', {777, 3.141593}};
|
||||
//[pfr_quick_examples_structure_to_tuple
|
||||
// C++17 is required
|
||||
// C++17 or Loophole is required
|
||||
std::tuple<char, foo> t = boost::pfr::structure_to_tuple(var);
|
||||
std::get<1>(t) = foo{1, 2};
|
||||
//]
|
||||
@@ -203,7 +203,7 @@ void test_examples() {
|
||||
{
|
||||
bar var{'A', {777, 3.141593}};
|
||||
//[pfr_quick_examples_structure_tie
|
||||
// C++17 is required
|
||||
// C++17 or Loophole is required
|
||||
std::tuple<char&, foo&> t = boost::pfr::structure_tie(var);
|
||||
std::get<1>(t) = foo{1, 2};
|
||||
//]
|
||||
|
||||
@@ -49,4 +49,15 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(maybe_unused)
|
||||
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_PFR_MAYBE_UNUSED
|
||||
# define BOOST_PFR_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CONFIG_HPP
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <boost/pfr/detail/make_flat_tuple_of_references.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/size_array.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -32,10 +33,7 @@ namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
template <class T> struct identity{
|
||||
template <class T> struct identity {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
@@ -508,7 +506,10 @@ template <class T>
|
||||
constexpr auto internal_tuple_with_same_alignment() noexcept {
|
||||
typedef typename std::remove_cv<T>::type type;
|
||||
|
||||
static_assert(std::is_pod<type>::value, "====================> Boost.PFR: Type can not be used is flat_ functions, because it's not POD");
|
||||
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"
|
||||
);
|
||||
static_assert(!std::is_reference<type>::value, "====================> Boost.PFR: Not applyable");
|
||||
constexpr auto res = detail::as_flat_tuple_impl<type>(
|
||||
detail::make_index_sequence< decltype(detail::flat_array_of_type_ids<type>())::size() >()
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
#include <boost/pfr/detail/unsafe_declval.hpp>
|
||||
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -59,12 +60,6 @@ struct tag {
|
||||
friend auto loophole(tag<T,N>);
|
||||
};
|
||||
|
||||
// For returning non default constructible types. Never used at runtime! GCC's std::declval may not be used in potentionally evaluated contexts, so it does not work here.
|
||||
template <class T> constexpr T& unsafe_declval_like() noexcept {
|
||||
T* ptr = nullptr;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
// The definitions of friend functions.
|
||||
template <class T, class U, std::size_t N, bool B>
|
||||
struct fn_def_lref {
|
||||
@@ -75,13 +70,13 @@ struct fn_def_lref {
|
||||
// To workaround the issue, we check that the type U is movable, and move it in that case.
|
||||
using no_extents_t = std::remove_all_extents_t<U>;
|
||||
return static_cast< std::conditional_t<std::is_move_constructible<no_extents_t>::value, no_extents_t&&, no_extents_t&> >(
|
||||
boost::pfr::detail::unsafe_declval_like<no_extents_t>()
|
||||
boost::pfr::detail::unsafe_declval<no_extents_t&>()
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class T, class U, std::size_t N, bool B>
|
||||
struct fn_def_rref {
|
||||
friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval_like< std::remove_all_extents_t<U> >()); }
|
||||
friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval< std::remove_all_extents_t<U>& >()); }
|
||||
};
|
||||
|
||||
|
||||
@@ -193,7 +188,7 @@ decltype(auto) tie_or_value(T& val, std::enable_if_t<std::is_enum<std::remove_re
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto tie_or_value(T& val, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
|
||||
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."
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define BOOST_PFR_DETAIL_CORE17_HPP
|
||||
|
||||
#include <boost/pfr/detail/core17_generated.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/for_each_field_impl.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
|
||||
@@ -44,6 +45,16 @@ static_assert(
|
||||
);
|
||||
#endif // #ifndef _MSC_VER
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
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."
|
||||
);
|
||||
typedef size_t_<boost::pfr::detail::fields_count<T>()> fields_count_tag;
|
||||
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
|
||||
}
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
# error C++17 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
@@ -1025,16 +1024,10 @@ constexpr auto tie_as_tuple(T& val, size_t_<100>) noexcept {
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
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."
|
||||
);
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
|
||||
template <class T, std::size_t I>
|
||||
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`");
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
|
||||
struct success{};
|
||||
struct success{};
|
||||
|
||||
template <template <class, class> class Detector, class Tleft, class Tright>
|
||||
struct not_appliable {
|
||||
static constexpr bool value = std::is_same<
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
#include <boost/pfr/detail/unsafe_declval.hpp>
|
||||
|
||||
#include <climits> // CHAR_BIT
|
||||
#include <type_traits>
|
||||
@@ -24,36 +26,40 @@
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
///////////////////// 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; // Undefined, allows initialization of reference fields (T& and const T&)
|
||||
template <class Type> constexpr operator Type&() const noexcept { // Allows initialization of reference fields (T& and const T&)
|
||||
return detail::unsafe_declval<Type&>();
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////// 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; // Undefined, 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&&>();
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////// Structure that can be converted to reference to anything except reference to T
|
||||
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
///////////////////// Hand-made is_aggregate_initializable_n<T> trait
|
||||
|
||||
// Structure that can be converted to reference to anything except reference to T
|
||||
template <class T, bool IsCopyConstructible>
|
||||
struct ubiq_constructor_except {
|
||||
std::size_t ignore;
|
||||
template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&> () const noexcept; // Undefined
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ubiq_constructor_except<T, false> {
|
||||
std::size_t ignore;
|
||||
template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&&> () const noexcept; // Undefined
|
||||
};
|
||||
|
||||
|
||||
///////////////////// Hand-made is_aggregate_initializable_n<T> trait
|
||||
|
||||
// `std::is_constructible<T, ubiq_constructor_except<T>>` consumes a lot of time, so we made a separate lazy trait for it.
|
||||
template <std::size_t N, class T> struct is_single_field_and_aggregate_initializable: std::false_type {};
|
||||
template <class T> struct is_single_field_and_aggregate_initializable<1, T>: std::integral_constant<
|
||||
@@ -61,7 +67,8 @@ template <class T> struct is_single_field_and_aggregate_initializable<1, T>: std
|
||||
> {};
|
||||
|
||||
// Hand-made is_aggregate<T> trait:
|
||||
// Aggregates could be constructed from `decltype(ubiq_?ref_constructor{I})...` but report that there's no constructor from `decltype(ubiq_?ref_constructor{I})...`
|
||||
// Before C++20 aggregates could be constructed from `decltype(ubiq_?ref_constructor{I})...` but type traits report that
|
||||
// there's no constructor from `decltype(ubiq_?ref_constructor{I})...`
|
||||
// Special case for N == 1: `std::is_constructible<T, ubiq_?ref_constructor>` returns true if N == 1 and T is copy/move constructible.
|
||||
template <class T, std::size_t N>
|
||||
struct is_aggregate_initializable_n {
|
||||
@@ -80,6 +87,8 @@ struct is_aggregate_initializable_n {
|
||||
;
|
||||
};
|
||||
|
||||
#endif // #ifndef __cpp_lib_is_aggregate
|
||||
|
||||
///////////////////// Helper for SFINAE on fields count
|
||||
template <class T, std::size_t... I, class /*Enable*/ = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
|
||||
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
|
||||
@@ -213,7 +222,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_standard_layout<type>::value, // Does not return `true` for structs that have non standard layout members.
|
||||
|| std::is_scalar<type>::value,
|
||||
"====================> Boost.PFR: Type must be aggregate initializable."
|
||||
);
|
||||
#endif
|
||||
@@ -229,10 +238,12 @@ constexpr std::size_t fields_count() noexcept {
|
||||
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT); // We multiply by CHAR_BIT because the type may have bitfields in T
|
||||
constexpr std::size_t result = detail::detect_fields_count_dispatch<type>(size_t_<max_fields_count>{}, 1L, 1L);
|
||||
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
static_assert(
|
||||
is_aggregate_initializable_n<type, result>::value,
|
||||
"====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported."
|
||||
);
|
||||
#endif
|
||||
|
||||
static_assert(
|
||||
result != 0 || std::is_empty<type>::value || std::is_fundamental<type>::value || std::is_reference<type>::value,
|
||||
|
||||
18
include/boost/pfr/detail/size_t_.hpp
Normal file
18
include/boost/pfr/detail/size_t_.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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_SIZE_T_HPP
|
||||
#define BOOST_PFR_DETAIL_SIZE_T_HPP
|
||||
#pragma once
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_SIZE_T_HPP
|
||||
36
include/boost/pfr/detail/unsafe_declval.hpp
Normal file
36
include/boost/pfr/detail/unsafe_declval.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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_UNSAFE_DECLVAL_HPP
|
||||
#define BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
// This function serves as a link-time assert. If linker requires it, then
|
||||
// `unsafe_declval()` is used at runtime.
|
||||
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,
|
||||
// so we reinvent it.
|
||||
template <class T>
|
||||
constexpr T unsafe_declval() noexcept {
|
||||
report_if_you_see_link_error_with_this_function();
|
||||
|
||||
typename std::remove_reference<T>::type* ptr = 0;
|
||||
ptr += 42; // suppresses 'null pointer dereference' warnings
|
||||
return static_cast<T>(*ptr);
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
|
||||
@@ -54,26 +54,26 @@
|
||||
/// std::size_t hash_value(const T& value) noexcept;
|
||||
/// \endcode
|
||||
|
||||
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
|
||||
static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
|
||||
static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
|
||||
static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
|
||||
static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
|
||||
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> \
|
||||
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> \
|
||||
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
::boost::pfr::flat_read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
static inline std::size_t hash_value(const T& v) noexcept { \
|
||||
return ::boost::pfr::flat_hash<T>{}(v); \
|
||||
} \
|
||||
#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
|
||||
|
||||
@@ -41,7 +41,7 @@ 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_pod<T>::value,
|
||||
std::is_same<T, U>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
bool
|
||||
>;
|
||||
|
||||
@@ -96,19 +96,28 @@ namespace boost { namespace pfr { namespace detail {
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_ostream<Char, Traits>&> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
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_pod<T>::value, std::basic_istream<Char, Traits>&> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
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_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
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
|
||||
|
||||
@@ -47,7 +47,7 @@ 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_pod<T>::value,
|
||||
not_appliable<Detector, T const&, T const&>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
bool
|
||||
>::type;
|
||||
|
||||
@@ -62,13 +62,15 @@ namespace detail {
|
||||
|
||||
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_pod<Type>::value,
|
||||
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_pod<Type>::value,
|
||||
not_appliable<istreamable_detector, Stream&, Type&>::value && std::is_trivial<Type>::value
|
||||
&& std::is_standard_layout<Type>::value,
|
||||
Stream&
|
||||
>::type;
|
||||
} // namespace detail
|
||||
@@ -134,7 +136,10 @@ namespace flat_ops {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,26 +52,26 @@
|
||||
/// std::size_t hash_value(const T& value);
|
||||
/// \endcode
|
||||
|
||||
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
|
||||
static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
|
||||
static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
|
||||
static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
|
||||
static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
|
||||
template <class Char, class Traits> \
|
||||
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> \
|
||||
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
::boost::pfr::read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
static inline std::size_t hash_value(const T& v) { \
|
||||
return ::boost::pfr::hash<T>{}(v); \
|
||||
} \
|
||||
#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); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
#endif // BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
|
||||
|
||||
@@ -241,7 +241,10 @@ template <class T> struct hash {
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
x,
|
||||
[&result](const auto& lhs) {
|
||||
result = detail::hash_impl<0, fields_count_val>::compute(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>{}
|
||||
);
|
||||
|
||||
@@ -94,13 +94,19 @@ namespace boost { namespace pfr { namespace detail {
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_ostream<Char, Traits>&> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
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_pod<T>::value, std::basic_istream<Char, Traits>&> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace boost { namespace pfr {
|
||||
/// \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<std::remove_reference_t<T>>();
|
||||
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));
|
||||
@@ -46,7 +46,10 @@ void write(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
value,
|
||||
[&out](const auto& val) {
|
||||
detail::print_impl<0, fields_count_val>::print(out, 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>{}
|
||||
);
|
||||
@@ -70,7 +73,7 @@ void write(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
/// \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<std::remove_reference_t<T>>();
|
||||
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) );
|
||||
@@ -86,7 +89,10 @@ void read(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
value,
|
||||
[&in](const auto& val) {
|
||||
detail::read_impl<0, fields_count_val>::read(in, 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>{}
|
||||
);
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace ops {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
static std::enable_if_t<std::is_trivial<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
return hash<T>{}(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,12 @@ PROLOGUE = """// Copyright (c) 2016-2020 Antony Polukhin
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
# error C++17 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
@@ -65,16 +64,10 @@ constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class<
|
||||
|
||||
############################################################################################################################
|
||||
EPILOGUE = """
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
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."
|
||||
);
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
|
||||
template <class T, std::size_t I>
|
||||
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`");
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
@@ -83,16 +76,6 @@ constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
"""
|
||||
|
||||
############################################################################################################################
|
||||
generate_sfinae_attempts = False
|
||||
|
||||
|
||||
if generate_sfinae_attempts:
|
||||
print """
|
||||
template <class T, std::size_t I>
|
||||
constexpr auto tie_as_tuple(T& val, size_t_<I>) noexcept {
|
||||
return tie_as_tuple(val, size_t_<I - 1>{});
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
indexes = " a"
|
||||
@@ -125,10 +108,4 @@ for i in xrange(1, funcs_count):
|
||||
|
||||
print "}\n"
|
||||
|
||||
if generate_sfinae_attempts:
|
||||
print "template <class T>"
|
||||
print "constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + "> v) noexcept"
|
||||
print " ->decltype( ::boost::pfr::detail::tie_as_tuple0(std::forward<T>(val), v) )"
|
||||
print "{ return ::boost::pfr::detail::tie_as_tuple0(std::forward<T>(val), v); }\n"
|
||||
|
||||
print EPILOGUE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2016-2019, Antony Polukhin.
|
||||
# Copyright (C) 2016-2020, Antony Polukhin.
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -99,13 +99,13 @@ test-suite pfr
|
||||
[ 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 ]
|
||||
#[ 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 ]
|
||||
#[ 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 ]
|
||||
|
||||
@@ -143,6 +143,7 @@ test-suite pfr
|
||||
[ 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 ]
|
||||
@@ -176,6 +177,7 @@ test-suite pfr
|
||||
[ 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 ]
|
||||
|
||||
@@ -39,10 +39,11 @@ struct comparable_struct {
|
||||
|
||||
BOOST_PFR_TEST_FUNCTIONS_FOR(comparable_struct)
|
||||
|
||||
void test_comparable_struct() {
|
||||
comparable_struct s1 {0, 1, false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, false, 6,7,8,9,10,11111};
|
||||
template <typename Struct>
|
||||
void test_some_comparable_struct() {
|
||||
Struct s1 {0, 1, false, 6,7,8,9,10,11};
|
||||
Struct s2 = s1;
|
||||
Struct s3 {0, 1, false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST_EQ(s1, s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
@@ -56,7 +57,7 @@ void test_comparable_struct() {
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
Struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
@@ -67,6 +68,10 @@ void test_comparable_struct() {
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
test_some_comparable_struct<comparable_struct>();
|
||||
}
|
||||
|
||||
struct empty { operator std::string() { return "empty{}"; } };
|
||||
BOOST_PFR_TEST_FUNCTIONS_FOR(empty)
|
||||
|
||||
@@ -105,12 +110,58 @@ void test_implicit_conversions() {
|
||||
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_TEST_FUNCTIONS_FOR
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
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)
|
||||
|
||||
|
||||
struct other_anonymous_struct {
|
||||
anonymous_comparable_struct a,b;
|
||||
};
|
||||
|
||||
BOOST_PFR_TEST_FUNCTIONS_FOR(other_anonymous_struct)
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<anonymous_comparable_struct> {
|
||||
std::size_t operator()(const anonymous_comparable_struct& val) const noexcept {
|
||||
return hash_value(val);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void test_anonymous_comparable_struct() {
|
||||
test_some_comparable_struct<anonymous_comparable_struct>();
|
||||
}
|
||||
|
||||
void test_nested_anonymous_comparable_struct() {
|
||||
other_anonymous_struct s1{
|
||||
{0, 1, false, 6,7,8,9,10,11},
|
||||
{0, 1, false, 6,7,8,9,10,11},
|
||||
};
|
||||
auto s2 = s1;
|
||||
|
||||
BOOST_TEST_EQ(s1, s2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_with_contatiners<std::less<>>();
|
||||
test_with_contatiners<std::greater<>>();
|
||||
test_implicit_conversions();
|
||||
test_anonymous_comparable_struct();
|
||||
test_nested_anonymous_comparable_struct();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ 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
|
||||
|
||||
|
||||
@@ -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,10 +11,11 @@
|
||||
# error Misused test
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct X {
|
||||
X() = delete;
|
||||
X(X&&) = default;
|
||||
X(const X&) = delete;
|
||||
|
||||
@@ -23,6 +24,9 @@ struct X {
|
||||
};
|
||||
struct S { X x0; X x1; int x2; X x3; };
|
||||
|
||||
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, "");
|
||||
@@ -45,6 +49,8 @@ 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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -58,8 +58,8 @@ void test_counts_on_multiple_chars_impl() {
|
||||
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]
|
||||
// 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, "");
|
||||
@@ -122,7 +122,5 @@ void test_counts_on_multiple_chars() {
|
||||
|
||||
int main() {
|
||||
test_counts_on_multiple_chars< BOOST_PFR_RUN_TEST_ON >();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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.hpp"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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.hpp"
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ struct non_default_constructible {
|
||||
T val_;
|
||||
|
||||
non_default_constructible() = delete;
|
||||
template <class U> non_default_constructible(U&& v){}
|
||||
template <class U> non_default_constructible(U&& /*v*/){}
|
||||
};
|
||||
|
||||
struct Foo {
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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 <string>
|
||||
#include "boost/pfr/precise.hpp"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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"
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ struct optional_like {
|
||||
T val_;
|
||||
|
||||
optional_like() = default;
|
||||
template <class U> optional_like(U&& v){}
|
||||
template <class U> optional_like(U&& /*v*/){}
|
||||
};
|
||||
|
||||
struct Foo {
|
||||
|
||||
94
test/precise/tie_anonymous.cpp
Normal file
94
test/precise/tie_anonymous.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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/precise/ops.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(__has_include)
|
||||
# if __has_include(<optional>)
|
||||
# include <optional>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace some {
|
||||
struct struct1{ int i; };
|
||||
struct struct2{ int i; };
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
struct anon_with_optional {
|
||||
std::string a;
|
||||
std::optional<some::struct1> b;
|
||||
std::optional<some::struct2> c;
|
||||
|
||||
};
|
||||
|
||||
struct other_anon_with_optional {
|
||||
std::string a;
|
||||
int b;
|
||||
std::optional<anon_with_optional> c;
|
||||
std::optional<some::struct2> d;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
struct other_anon {
|
||||
int data;
|
||||
};
|
||||
|
||||
struct anon {
|
||||
other_anon a;
|
||||
other_anon b;
|
||||
};
|
||||
|
||||
void test_in_anon_ns() {
|
||||
anon x{{1}, {2}};
|
||||
|
||||
auto v = boost::pfr::structure_tie(x);
|
||||
|
||||
BOOST_TEST_EQ(std::get<0>(v).data, 1);
|
||||
BOOST_TEST_EQ(std::get<1>(v).data, 2);
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
other_anon_with_optional opt{"test", {}, {}, {}};
|
||||
auto opt_val = boost::pfr::structure_tie(opt);
|
||||
BOOST_TEST_EQ(std::get<0>(opt_val), "test");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void test_in_non_non_ns() {
|
||||
anon x{{1}, {2}};
|
||||
|
||||
auto v = boost::pfr::structure_tie(x);
|
||||
|
||||
BOOST_TEST_EQ(std::get<0>(v).data, 1);
|
||||
BOOST_TEST_EQ(std::get<1>(v).data, 2);
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
other_anon_with_optional opt{"test again", {}, {}, {}};
|
||||
auto opt_val = boost::pfr::structure_tie(opt);
|
||||
BOOST_TEST_EQ(std::get<0>(opt_val), "test again");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_in_anon_ns();
|
||||
testing::test_in_non_non_ns();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user