2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-22 05:22:32 +00:00

Compare commits

...

40 Commits
1.0.0 ... 1.0.4

Author SHA1 Message Date
Antony Polukhin
50d58a2e84 Clean up and update the docs 2020-08-19 23:02:34 +03:00
Antony Polukhin
76ac44a9ca Add missing include 2020-08-19 20:41:07 +03:00
Antony Polukhin
4205a2e553 Improve diagnostics for structures with huge amount of fields 2020-08-19 19:45:05 +03:00
Antony Polukhin
89b1d45ff7 fix definition 2020-08-16 10:59:27 +03:00
Antony Polukhin
26867f47b7 fix warnings in tests 2020-08-16 10:58:36 +03:00
Antony Polukhin
b9166fd38e avoid copy-paste 2020-08-16 09:54:53 +03:00
Antony Polukhin
915bd9217c add link-time assertion to the unsafe_declval() function 2020-08-16 09:51:07 +03:00
Antony Polukhin
0885412a7d MSVC test fix 2020-08-13 21:46:06 +03:00
Antony Polukhin
86ebac6e0c reproduced and fixed the "type without linkage" error 2020-08-13 20:38:22 +03:00
Antony Polukhin
39e9b4c5fe attempt to reproduce a "type without linkage" warning 2020-08-13 18:27:00 +03:00
Antony Polukhin
01fd8db5b4 fix warning and add more tests 2020-08-13 18:13:57 +03:00
Antony Polukhin
077ea5451c Fix issues found by Boosts inspect tool 2020-07-07 09:42:19 +03:00
Antony Polukhin
3a36467d96 Typo fix 2020-07-07 09:29:27 +03:00
Antony Polukhin
3eee880972 Test on Clang-10 in C++20 mode 2020-07-07 09:28:40 +03:00
Antony Polukhin
41a22fcd21 Avoid defining complilcated is_aggregate_initializable_n if std::is_aggregate available 2020-07-07 09:28:21 +03:00
Antony Polukhin
e354ba8b25 Simplify assertions if std::is_aggregate is available 2020-07-07 09:16:06 +03:00
Antony Polukhin
7a0f5f90df Disable weird tests 2020-07-06 21:48:28 +03:00
Antony Polukhin
041b0dd226 Fix attempt 2020-07-06 21:27:25 +03:00
Antony Polukhin
ff1c5e3a7f One step closer to working C++20 solution (1) 2020-07-06 20:42:47 +03:00
Antony Polukhin
4c48a220c2 One step closer to working C++20 solution 2020-07-06 20:12:50 +03:00
Antony Polukhin
ed6fe1431d Attempt to find function that breaks GCC-10 constexpr 2020-07-06 18:45:18 +03:00
Antony Polukhin
16db439e8c More C++20 fixes 2020-07-06 18:28:19 +03:00
Antony Polukhin
c3ccb7a525 Fixes for C++20 2020-07-06 18:07:40 +03:00
Antony Polukhin
d6e44dde8f fix 2020-07-06 17:23:13 +03:00
Antony Polukhin
63b5f1f791 GCC-10 fixes 2020-07-06 17:17:00 +03:00
Antony Polukhin
dc814c7e7f build fix for GCC-10 2020-07-06 17:06:09 +03:00
Antony Polukhin
671cc3f282 typo fixed 2020-07-06 16:39:52 +03:00
Antony Polukhin
8ca6b531a6 Attempt to fix PFRs error detection on GCC-10 2020-07-06 16:30:23 +03:00
Antony Polukhin
f24698f131 Updates for C++20 mode (workaround compiler idiosyncrasies 3) 2020-07-06 14:24:02 +03:00
Antony Polukhin
950e4aa0ee disable more weird tests 2020-07-06 14:08:50 +03:00
Antony Polukhin
b9bea47e4f Comment out weird test 2020-07-06 13:54:05 +03:00
Antony Polukhin
6d1fc03667 Avoid using deprecated std::is_pod 2020-07-06 13:40:24 +03:00
Antony Polukhin
ba65dd23ef Updates for C++20 mode (workaround compiler idiosyncrasies 2) 2020-07-06 13:22:17 +03:00
Antony Polukhin
5b28535b8e Updates for C++20 mode (workaround compiler idiosyncrasies) 2020-07-06 13:01:40 +03:00
Antony Polukhin
802c7033ba Updates for C++20 mode (refs #44) 2020-07-06 12:41:53 +03:00
Antony Polukhin
4a593c0628 CI experiment: use GCC-10 2020-07-06 12:10:12 +03:00
Antony Polukhin
b603f6fdef CI experiment: use Bionic 2020-07-06 11:49:04 +03:00
Antony Polukhin
1a620d36dd CI fixes (1) 2020-07-06 11:35:17 +03:00
Antony Polukhin
93cb89cf05 revert the gcc-10 CI attempt 2020-07-05 19:15:47 +03:00
Antony Polukhin
d2964544a4 attempt to add GCC-10 to CI 2020-07-05 19:08:57 +03:00
35 changed files with 572 additions and 302 deletions

View File

@@ -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/

View File

@@ -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

View File

@@ -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};
//]

View File

@@ -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

View File

@@ -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() >()

View File

@@ -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."

View File

@@ -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(

View File

@@ -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

View File

@@ -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<

View File

@@ -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,

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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>{}
);

View File

@@ -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;
}

View File

@@ -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>{}
);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 ]

View File

@@ -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();
}

View File

@@ -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

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,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

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

@@ -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;
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 {

View 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();
}