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

Compare commits

...

9 Commits
2.0.0 ... 2.0.1

Author SHA1 Message Date
Antony Polukhin
a5f84b38a6 Disable constexpr_ops test on MSVC 2020-12-17 20:28:38 +03:00
Antony Polukhin
e88e44cc14 comparison functions are now constexpr (fixes #52) 2020-12-16 18:42:40 +03:00
Antony Polukhin
f28952c544 fix attempt for #61 2020-12-16 17:38:15 +03:00
Antony Polukhin
eb37b11dfc attempt to fix test 2020-12-16 11:58:39 +03:00
Antony Polukhin
2719abe88c fix typos in SimpleAggregate (fixes #63) 2020-12-16 10:56:53 +03:00
Antony Polukhin
01af26370f Merge pull request #64 from eldiener/develop
Add "cxxstd" json field. The "cxxstd" json field is being added to ea…
2020-12-16 10:53:09 +03:00
Edward Diener
eb7a7a2d92 Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries whose minumum C++ standard compilation level is C++11 on up. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. 2020-12-16 00:42:20 -05:00
Antony Polukhin
33b5003883 fixes 2020-12-15 15:46:17 +03:00
Antony Polukhin
99f5037a00 add test on reflecting structure with std::optional<std::chrono::seconds> (refs #61) 2020-11-28 20:30:22 +03:00
9 changed files with 196 additions and 28 deletions

View File

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

View File

@@ -29,7 +29,11 @@ namespace boost { namespace pfr { namespace detail {
///////////////////// Structure that can be converted to reference to anything
struct ubiq_lref_constructor {
std::size_t ignore;
template <class Type> constexpr operator Type&() const && noexcept { // Allows initialization of reference fields (T& and const T&)
template <class Type> constexpr operator Type&() const && noexcept { // tweak for template_unconstrained.cpp like cases
return detail::unsafe_declval<Type&>();
};
template <class Type> constexpr operator Type&() const & noexcept { // tweak for optional_chrono.cpp like cases
return detail::unsafe_declval<Type&>();
};
};

View File

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

View File

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

View File

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

View File

@@ -11,5 +11,6 @@
"category": [
"Data",
"Metaprogramming"
]
],
"cxxstd": "14"
}

View File

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

View File

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

View File

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