mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 16:32:13 +00:00
Compare commits
10 Commits
boost-1.75
...
help
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3daf98c9e9 | ||
|
|
a5f84b38a6 | ||
|
|
e88e44cc14 | ||
|
|
f28952c544 | ||
|
|
eb37b11dfc | ||
|
|
2719abe88c | ||
|
|
01af26370f | ||
|
|
eb7a7a2d92 | ||
|
|
33b5003883 | ||
|
|
99f5037a00 |
10
doc/pfr.qbk
10
doc/pfr.qbk
@@ -438,25 +438,25 @@ error: static_assert failed "====================> Boost.PFR: For safety reasons
|
||||
|
||||
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
|
||||
|
||||
Boost.PFR library works with types that satisfy the requirements of `SimpleAggregare`: aggregate types without base classes, `const` fields, references, or C arrays:
|
||||
Boost.PFR library works with types that satisfy the requirements of `SimpleAggregate`: aggregate types without base classes, `const` fields, references, or C arrays:
|
||||
|
||||
```
|
||||
struct simple_aggregate { // SimpleAggregare
|
||||
struct simple_aggregate { // SimpleAggregate
|
||||
std::string name;
|
||||
int age;
|
||||
boost::uuids::uuid uuid;
|
||||
};
|
||||
|
||||
struct empty { // SimpleAggregare
|
||||
struct empty { // SimpleAggregate
|
||||
};
|
||||
|
||||
struct aggregate : empty { // not a SimpleAggregare
|
||||
struct aggregate : empty { // not a SimpleAggregate
|
||||
std::string name;
|
||||
int age;
|
||||
boost::uuids::uuid uuid;
|
||||
};
|
||||
```
|
||||
The library may work with aggregates that don't satisfy the requirements of `SimpleAggregare`, but the behavior tends to be non-portable.
|
||||
The library may work with aggregates that don't satisfy the requirements of `SimpleAggregate`, but the behavior tends to be non-portable.
|
||||
|
||||
[h2 Configuration Macro]
|
||||
|
||||
|
||||
@@ -29,7 +29,11 @@ namespace boost { namespace pfr { namespace detail {
|
||||
///////////////////// Structure that can be converted to reference to anything
|
||||
struct ubiq_lref_constructor {
|
||||
std::size_t ignore;
|
||||
template <class Type> constexpr operator Type&() const && noexcept { // Allows initialization of reference fields (T& and const T&)
|
||||
template <class Type> constexpr operator Type&() const && noexcept { // tweak for template_unconstrained.cpp like cases
|
||||
return detail::unsafe_declval<Type&>();
|
||||
};
|
||||
|
||||
template <class Type> constexpr operator Type&() const & noexcept { // tweak for optional_chrono.cpp like cases
|
||||
return detail::unsafe_declval<Type&>();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace boost { namespace pfr { namespace detail {
|
||||
}
|
||||
|
||||
template <template <std::size_t, std::size_t> class Visitor, class T, class U>
|
||||
bool binary_visit(const T& x, const U& y) {
|
||||
constexpr bool binary_visit(const T& x, const U& y) {
|
||||
constexpr std::size_t fields_count_lhs = detail::fields_count<std::remove_reference_t<T>>();
|
||||
constexpr std::size_t fields_count_rhs = detail::fields_count<std::remove_reference_t<U>>();
|
||||
constexpr std::size_t fields_count_min = detail::min_size(fields_count_lhs, fields_count_rhs);
|
||||
|
||||
@@ -82,13 +82,13 @@ namespace detail {
|
||||
///
|
||||
/// \returns true if lhs is equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
detail::enable_not_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr detail::enable_not_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::eq_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload eq
|
||||
template <class T, class U>
|
||||
detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
|
||||
constexpr detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
@@ -97,13 +97,13 @@ detail::enable_eq_comp_t<T, U> eq(const T& lhs, const U& rhs) {
|
||||
///
|
||||
/// \returns true if lhs is not equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
detail::enable_not_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr detail::enable_not_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::ne_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload ne
|
||||
template <class T, class U>
|
||||
detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
|
||||
constexpr detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
|
||||
return lhs != rhs;
|
||||
}
|
||||
|
||||
@@ -112,13 +112,13 @@ detail::enable_ne_comp_t<T, U> ne(const T& lhs, const U& rhs) {
|
||||
///
|
||||
/// \returns true if lhs is less than rhs; false otherwise
|
||||
template <class T, class U>
|
||||
detail::enable_not_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr detail::enable_not_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::lt_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload lt
|
||||
template <class T, class U>
|
||||
detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
|
||||
constexpr detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
@@ -127,13 +127,13 @@ detail::enable_lt_comp_t<T, U> lt(const T& lhs, const U& rhs) {
|
||||
///
|
||||
/// \returns true if lhs is greater than rhs; false otherwise
|
||||
template <class T, class U>
|
||||
detail::enable_not_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr detail::enable_not_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::gt_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload gt
|
||||
template <class T, class U>
|
||||
detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
|
||||
constexpr detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
|
||||
return lhs > rhs;
|
||||
}
|
||||
|
||||
@@ -142,13 +142,13 @@ detail::enable_gt_comp_t<T, U> gt(const T& lhs, const U& rhs) {
|
||||
///
|
||||
/// \returns true if lhs is less or equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
detail::enable_not_le_comp_t<T, U> le(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr detail::enable_not_le_comp_t<T, U> le(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::le_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload le
|
||||
template <class T, class U>
|
||||
detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
|
||||
constexpr detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
|
||||
return lhs <= rhs;
|
||||
}
|
||||
|
||||
@@ -157,13 +157,13 @@ detail::enable_le_comp_t<T, U> le(const T& lhs, const U& rhs) {
|
||||
///
|
||||
/// \returns true if lhs is greater or equal to rhs; false otherwise
|
||||
template <class T, class U>
|
||||
detail::enable_not_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr detail::enable_not_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) noexcept {
|
||||
return boost::pfr::ge_fields(lhs, rhs);
|
||||
}
|
||||
|
||||
/// \overload ge
|
||||
template <class T, class U>
|
||||
detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
|
||||
constexpr detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
|
||||
return lhs >= rhs;
|
||||
}
|
||||
|
||||
@@ -172,13 +172,13 @@ detail::enable_ge_comp_t<T, U> ge(const T& lhs, const U& rhs) {
|
||||
///
|
||||
/// \returns std::size_t with hash of the value
|
||||
template <class T>
|
||||
detail::enable_not_hashable_t<T> hash_value(const T& value) noexcept {
|
||||
constexpr detail::enable_not_hashable_t<T> hash_value(const T& value) noexcept {
|
||||
return boost::pfr::hash_fields(value);
|
||||
}
|
||||
|
||||
/// \overload hash_value
|
||||
template <class T>
|
||||
detail::enable_hashable_t<T> hash_value(const T& value) {
|
||||
constexpr detail::enable_hashable_t<T> hash_value(const T& value) {
|
||||
return std::hash<T>{}(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace boost { namespace pfr {
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
bool eq_fields(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr bool eq_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace boost { namespace pfr {
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
bool ne_fields(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr bool ne_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::not_equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace boost { namespace pfr {
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
bool gt_fields(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr bool gt_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::greater_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace boost { namespace pfr {
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
bool lt_fields(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr bool lt_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::less_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace boost { namespace pfr {
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
bool ge_fields(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr bool ge_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::greater_equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace boost { namespace pfr {
|
||||
/// `R` are the results of calling `std::tie` on first `N` fields of `lhs` and
|
||||
// `rhs` respectively; `N` is `std::min(tuple_size_v<T>, tuple_size_v<U>)`.
|
||||
template <class T, class U>
|
||||
bool le_fields(const T& lhs, const U& rhs) noexcept {
|
||||
constexpr bool le_fields(const T& lhs, const U& rhs) noexcept {
|
||||
return detail::binary_visit<detail::less_equal_impl>(lhs, rhs);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,5 +11,7 @@
|
||||
"category": [
|
||||
"Data",
|
||||
"Metaprogramming"
|
||||
]
|
||||
],
|
||||
"std": [ "proposal" ],
|
||||
"cxxstd": "14"
|
||||
}
|
||||
|
||||
@@ -67,7 +67,9 @@ test-suite pfr_tests
|
||||
;
|
||||
|
||||
local BLACKLIST_TESTS_FOR_LOOPHOLE =
|
||||
constexpr_ops # Loophole is not constexpr usable because of the reinterpret_cast usage
|
||||
get_const_field # boost::pfr::get gives compile time error on const fields
|
||||
optional_chrono # boost::pfr::* has problems with std::optional, produces compile time error
|
||||
template_constructor # Template constructor in one of the fields of the aggregate
|
||||
tie_anonymous_const_field # boost::pfr::structure_tie gives compile time error on const fields
|
||||
;
|
||||
@@ -76,6 +78,7 @@ local BLACKLIST_TESTS_FOR_LOOPHOLE =
|
||||
# * reflecting a non literal type
|
||||
# * or calling boost::pfr::get and the result is a user defined structure
|
||||
local BLACKLIST_TESTS_FOR_CLASSIC =
|
||||
constexpr_ops
|
||||
get_const_field
|
||||
get_non_default_constructible
|
||||
get_rvalue
|
||||
@@ -83,6 +86,7 @@ local BLACKLIST_TESTS_FOR_CLASSIC =
|
||||
issue33
|
||||
motivating_example0
|
||||
motivating_example2
|
||||
optional_chrono
|
||||
optional_like
|
||||
read_write_non_literal
|
||||
template_constructor
|
||||
|
||||
81
test/run/constexpr_ops.cpp
Normal file
81
test/run/constexpr_ops.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/pfr/ops.hpp>
|
||||
#include <boost/pfr/io.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
#endif
|
||||
|
||||
union test_union {
|
||||
int i;
|
||||
float f;
|
||||
};
|
||||
|
||||
constexpr bool operator< (test_union l, test_union r) noexcept { return l.i < r.i; }
|
||||
constexpr bool operator<=(test_union l, test_union r) noexcept { return l.i <= r.i; }
|
||||
constexpr bool operator> (test_union l, test_union r) noexcept { return l.i > r.i; }
|
||||
constexpr bool operator>=(test_union l, test_union r) noexcept { return l.i >= r.i; }
|
||||
constexpr bool operator==(test_union l, test_union r) noexcept { return l.i == r.i; }
|
||||
constexpr bool operator!=(test_union l, test_union r) noexcept { return l.i != r.i; }
|
||||
|
||||
|
||||
template <class T>
|
||||
void test_constexpr_comparable() {
|
||||
using namespace boost::pfr;
|
||||
constexpr T s1 {110, 1, true, 6,17,8,9,10,11};
|
||||
constexpr T s2 = s1;
|
||||
constexpr T s3 {110, 1, true, 6,17,8,9,10,11111};
|
||||
static_assert(eq(s1, s2), "");
|
||||
static_assert(le(s1, s2), "");
|
||||
static_assert(ge(s1, s2), "");
|
||||
static_assert(!ne(s1, s2), "");
|
||||
static_assert(!eq(s1, s3), "");
|
||||
static_assert(ne(s1, s3), "");
|
||||
static_assert(lt(s1, s3), "");
|
||||
static_assert(gt(s3, s2), "");
|
||||
static_assert(le(s1, s3), "");
|
||||
static_assert(ge(s3, s2), "");
|
||||
}
|
||||
|
||||
namespace foo {
|
||||
struct comparable_struct {
|
||||
int i; short s; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
}
|
||||
|
||||
int main() {
|
||||
// MSVC fails to use strucutred bindings in constexpr:
|
||||
//
|
||||
// error C2131: expression did not evaluate to a constant
|
||||
// pfr/detail/functional.hpp(21): note: failure was caused by a read of a variable outside its lifetime
|
||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1927) || !BOOST_PFR_USE_CPP17
|
||||
test_constexpr_comparable<foo::comparable_struct>();
|
||||
|
||||
struct local_comparable_struct {
|
||||
int i; short s; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
test_constexpr_comparable<local_comparable_struct>();
|
||||
|
||||
struct local_comparable_struct_with_union {
|
||||
int i; short s; bool bl; int a,b,c,d,e; test_union u;
|
||||
};
|
||||
test_constexpr_comparable<local_comparable_struct>();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
78
test/run/optional_chrono.cpp
Normal file
78
test/run/optional_chrono.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <optional>
|
||||
|
||||
// This class mimics libc++ implementation of std::chrono::duration with unfxed LWG3050
|
||||
template <class Rep, class Period>
|
||||
class bogus_duration {
|
||||
public:
|
||||
bogus_duration() = default;
|
||||
|
||||
template <class T>
|
||||
explicit bogus_duration(const T& val,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<T, Rep>::value // <= libstdc++ fix for LWG3050 is 's/T/const T&/g'
|
||||
>::type* = nullptr)
|
||||
: rep_(val)
|
||||
{}
|
||||
|
||||
template <class Rep2, class Period2>
|
||||
bogus_duration(const bogus_duration<Rep2, Period2>& val,
|
||||
typename std::enable_if<std::is_convertible<Period2, Rep>::value>::type* = nullptr)
|
||||
: rep_(val)
|
||||
{}
|
||||
|
||||
Rep get_rep() const { return rep_; }
|
||||
|
||||
private:
|
||||
Rep rep_{0};
|
||||
};
|
||||
|
||||
struct struct_with_bogus_duration {
|
||||
std::optional<bogus_duration<long, char>> d0;
|
||||
std::optional<bogus_duration<long, char>> d1;
|
||||
};
|
||||
|
||||
struct struct_with_optional {
|
||||
std::optional<std::chrono::seconds> a;
|
||||
std::optional<std::chrono::milliseconds> b;
|
||||
std::optional<std::chrono::microseconds> c;
|
||||
std::optional<std::chrono::nanoseconds> d;
|
||||
std::optional<std::chrono::steady_clock::duration> e;
|
||||
std::optional<std::chrono::system_clock::duration> f;
|
||||
};
|
||||
|
||||
int main() {
|
||||
struct_with_optional val{
|
||||
std::chrono::seconds{1},
|
||||
std::chrono::seconds{2},
|
||||
std::chrono::seconds{3},
|
||||
std::chrono::seconds{4},
|
||||
std::chrono::seconds{5},
|
||||
std::chrono::seconds{6},
|
||||
};
|
||||
|
||||
using boost::pfr::get;
|
||||
BOOST_TEST(get<0>(val) == std::chrono::seconds{1});
|
||||
BOOST_TEST(get<1>(val) == std::chrono::seconds{2});
|
||||
BOOST_TEST(get<2>(val) == std::chrono::seconds{3});
|
||||
BOOST_TEST(get<3>(val) == std::chrono::seconds{4});
|
||||
BOOST_TEST(get<3>(val) > std::chrono::seconds{0});
|
||||
BOOST_TEST(get<3>(val) > std::chrono::seconds{0});
|
||||
|
||||
struct_with_bogus_duration val2{bogus_duration<long, char>{1}, bogus_duration<long, char>{2}};
|
||||
BOOST_TEST(get<0>(val2)->get_rep() == 1);
|
||||
BOOST_TEST(get<1>(val2)->get_rep() == 2);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user