mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-20 16:52:13 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0885412a7d | ||
|
|
86ebac6e0c | ||
|
|
39e9b4c5fe | ||
|
|
01fd8db5b4 | ||
|
|
077ea5451c | ||
|
|
3a36467d96 | ||
|
|
3eee880972 | ||
|
|
41a22fcd21 | ||
|
|
e354ba8b25 | ||
|
|
7a0f5f90df | ||
|
|
041b0dd226 | ||
|
|
ff1c5e3a7f | ||
|
|
4c48a220c2 | ||
|
|
ed6fe1431d | ||
|
|
16db439e8c | ||
|
|
c3ccb7a525 | ||
|
|
d6e44dde8f | ||
|
|
63b5f1f791 | ||
|
|
dc814c7e7f | ||
|
|
671cc3f282 | ||
|
|
8ca6b531a6 | ||
|
|
f24698f131 | ||
|
|
950e4aa0ee | ||
|
|
b9bea47e4f | ||
|
|
6d1fc03667 | ||
|
|
ba65dd23ef | ||
|
|
5b28535b8e | ||
|
|
802c7033ba | ||
|
|
4a593c0628 | ||
|
|
b603f6fdef | ||
|
|
1a620d36dd | ||
|
|
93cb89cf05 | ||
|
|
d2964544a4 |
64
.travis.yml
64
.travis.yml
@@ -2,7 +2,7 @@
|
||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Copyright Antony Polukhin 2014-2019.
|
||||
# Copyright Antony Polukhin 2014-2020.
|
||||
|
||||
#
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
@@ -10,30 +10,9 @@
|
||||
#
|
||||
# File revision #9 (with DIFF)
|
||||
|
||||
sudo: false
|
||||
language: cpp
|
||||
os: linux
|
||||
|
||||
env:
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BOOST_BRANCH=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be useful, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
|
||||
# This will force to use local repo content, instead of the Boost's default.
|
||||
- BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
|
||||
|
||||
# Global options for sanitizers
|
||||
- UBSAN_OPTIONS=print_stacktrace=1
|
||||
- LSAN_OPTIONS=verbosity=1:log_threads=1
|
||||
dist: bionic
|
||||
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
matrix:
|
||||
@@ -45,6 +24,14 @@ matrix:
|
||||
# sources: ubuntu-toolchain-r-test
|
||||
# packages: g++-6
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-10 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
|
||||
name: "GCC-10"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: ubuntu-toolchain-r-test
|
||||
packages: g++-10
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,17,2a toolset=gcc-8 cxxflags="--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="--coverage -lasan -lubsan"'
|
||||
name: "GCC-8"
|
||||
sudo: required # Required by leak sanitizer
|
||||
@@ -76,16 +63,16 @@ matrix:
|
||||
sources: llvm-toolchain-trusty-6
|
||||
packages: clang-6.0
|
||||
|
||||
- env: B2_ARGS='cxxstd=14,1z toolset=clang-8 cxxflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined"'
|
||||
name: "Clang-8, libc++"
|
||||
- env: B2_ARGS='cxxstd=14,17,20 toolset=clang-10 cxxflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined -DBOOST_TRAVISCI_BUILD" linkflags="-stdlib=libc++ --coverage -fsanitize=address,leak,undefined"'
|
||||
name: "Clang-10, libc++"
|
||||
sudo: required # Required by leak sanitizer
|
||||
addons:
|
||||
apt:
|
||||
sources: llvm-toolchain-trusty-8
|
||||
sources: llvm-toolchain-bionic-10
|
||||
packages:
|
||||
- clang-8
|
||||
- libc++-8-dev
|
||||
- libc++abi-8-dev
|
||||
- clang-10
|
||||
- libc++-10-dev
|
||||
- libc++abi-10-dev
|
||||
|
||||
# Sanitizers disabled for this toolset as they started causing link troubles:
|
||||
# hidden symbol `_ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE11__recommendEm' isn't defined
|
||||
@@ -108,6 +95,24 @@ addons:
|
||||
- python-yaml
|
||||
|
||||
before_install:
|
||||
# Autodetect Boost branch by using the following code: - BOOST_BRANCH=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be useful, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
|
||||
# This will force to use local repo content, instead of the Boost's default.
|
||||
- BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
|
||||
|
||||
# Global options for sanitizers
|
||||
- UBSAN_OPTIONS=print_stacktrace=1
|
||||
- LSAN_OPTIONS=verbosity=1:log_threads=1
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
|
||||
@@ -138,6 +143,7 @@ before_install:
|
||||
echo "using clang : 6 : clang++-6.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 7 : clang++-7.0 ;" >> ~/user-config.jam
|
||||
echo "using clang : 8 : clang++-8 ;" >> ~/user-config.jam
|
||||
echo "using clang : 10 : clang++-10 ;" >> ~/user-config.jam
|
||||
echo "using clang : libc++ : clang++-libc++ ;" >> ~/user-config.jam
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test/
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -508,7 +508,10 @@ template <class T>
|
||||
constexpr auto internal_tuple_with_same_alignment() noexcept {
|
||||
typedef typename std::remove_cv<T>::type type;
|
||||
|
||||
static_assert(std::is_pod<type>::value, "====================> Boost.PFR: Type can not be used is flat_ functions, because it's not POD");
|
||||
static_assert(
|
||||
std::is_trivial<type>::value && std::is_standard_layout<type>::value,
|
||||
"====================> Boost.PFR: Type can not be used is flat_ functions, because it's not POD"
|
||||
);
|
||||
static_assert(!std::is_reference<type>::value, "====================> Boost.PFR: Not applyable");
|
||||
constexpr auto res = detail::as_flat_tuple_impl<type>(
|
||||
detail::make_index_sequence< decltype(detail::flat_array_of_type_ids<type>())::size() >()
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
#include <boost/pfr/detail/unsafe_declval.hpp>
|
||||
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -59,12 +60,6 @@ struct tag {
|
||||
friend auto loophole(tag<T,N>);
|
||||
};
|
||||
|
||||
// For returning non default constructible types. Never used at runtime! GCC's std::declval may not be used in potentionally evaluated contexts, so it does not work here.
|
||||
template <class T> constexpr T& unsafe_declval_like() noexcept {
|
||||
T* ptr = nullptr;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
// The definitions of friend functions.
|
||||
template <class T, class U, std::size_t N, bool B>
|
||||
struct fn_def_lref {
|
||||
@@ -75,13 +70,13 @@ struct fn_def_lref {
|
||||
// To workaround the issue, we check that the type U is movable, and move it in that case.
|
||||
using no_extents_t = std::remove_all_extents_t<U>;
|
||||
return static_cast< std::conditional_t<std::is_move_constructible<no_extents_t>::value, no_extents_t&&, no_extents_t&> >(
|
||||
boost::pfr::detail::unsafe_declval_like<no_extents_t>()
|
||||
boost::pfr::detail::unsafe_declval<no_extents_t&>()
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class T, class U, std::size_t N, bool B>
|
||||
struct fn_def_rref {
|
||||
friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval_like< std::remove_all_extents_t<U> >()); }
|
||||
friend auto loophole(tag<T,N>) { return std::move(boost::pfr::detail::unsafe_declval< std::remove_all_extents_t<U>& >()); }
|
||||
};
|
||||
|
||||
|
||||
@@ -193,7 +188,7 @@ decltype(auto) tie_or_value(T& val, std::enable_if_t<std::is_enum<std::remove_re
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto tie_or_value(T& val, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
|
||||
auto tie_or_value(T& /*val*/, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define BOOST_PFR_DETAIL_CORE17_HPP
|
||||
|
||||
#include <boost/pfr/detail/core17_generated.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/for_each_field_impl.hpp>
|
||||
#include <boost/pfr/detail/rvalue_t.hpp>
|
||||
|
||||
@@ -44,6 +45,16 @@ static_assert(
|
||||
);
|
||||
#endif // #ifndef _MSC_VER
|
||||
|
||||
template <class T>
|
||||
constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
typedef size_t_<boost::pfr::detail::fields_count<T>()> fields_count_tag;
|
||||
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
|
||||
}
|
||||
|
||||
template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
# error C++17 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
@@ -1025,18 +1024,6 @@ 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{});
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
|
||||
struct success{};
|
||||
struct success{};
|
||||
|
||||
template <template <class, class> class Detector, class Tleft, class Tright>
|
||||
struct not_appliable {
|
||||
static constexpr bool value = std::is_same<
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
#include <boost/pfr/detail/unsafe_declval.hpp>
|
||||
|
||||
#include <climits> // CHAR_BIT
|
||||
#include <type_traits>
|
||||
@@ -24,36 +26,38 @@
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
///////////////////// 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 +65,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 +85,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 +220,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 +236,12 @@ constexpr std::size_t fields_count() noexcept {
|
||||
constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT); // We multiply by CHAR_BIT because the type may have bitfields in T
|
||||
constexpr std::size_t result = detail::detect_fields_count_dispatch<type>(size_t_<max_fields_count>{}, 1L, 1L);
|
||||
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
static_assert(
|
||||
is_aggregate_initializable_n<type, result>::value,
|
||||
"====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported."
|
||||
);
|
||||
#endif
|
||||
|
||||
static_assert(
|
||||
result != 0 || std::is_empty<type>::value || std::is_fundamental<type>::value || std::is_reference<type>::value,
|
||||
|
||||
18
include/boost/pfr/detail/size_t_.hpp
Normal file
18
include/boost/pfr/detail/size_t_.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PFR_DETAIL_SIZE_T_HPP
|
||||
#define BOOST_PFR_DETAIL_SIZE_T_HPP
|
||||
#pragma once
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_SIZE_T_HPP
|
||||
27
include/boost/pfr/detail/unsafe_declval.hpp
Normal file
27
include/boost/pfr/detail/unsafe_declval.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// 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 {
|
||||
|
||||
// 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() noexcept {
|
||||
typename std::remove_reference<T>::type* ptr = 0;
|
||||
ptr += 42; // killing 'null pointer dereference' heuristics of static analysis tools
|
||||
return static_cast<T>(*ptr);
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_UNSAFE_DECLVAL_HPP
|
||||
|
||||
@@ -54,26 +54,26 @@
|
||||
/// std::size_t hash_value(const T& value) noexcept;
|
||||
/// \endcode
|
||||
|
||||
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
|
||||
static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
|
||||
static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
|
||||
static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
|
||||
static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs); } \
|
||||
template <class Char, class Traits> \
|
||||
static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
|
||||
::boost::pfr::flat_write(out, value); \
|
||||
return out; \
|
||||
} \
|
||||
template <class Char, class Traits> \
|
||||
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
::boost::pfr::flat_read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
static inline std::size_t hash_value(const T& v) noexcept { \
|
||||
return ::boost::pfr::flat_hash<T>{}(v); \
|
||||
} \
|
||||
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs); } \
|
||||
template <class Char, class Traits> \
|
||||
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
|
||||
::boost::pfr::flat_write(out, value); \
|
||||
return out; \
|
||||
} \
|
||||
template <class Char, class Traits> \
|
||||
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
::boost::pfr::flat_read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) noexcept { \
|
||||
return ::boost::pfr::flat_hash<T>{}(v); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
#endif // BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class T, class U>
|
||||
using enable_flat_comparisons = std::enable_if_t<
|
||||
std::is_same<T, U>::value && std::is_pod<T>::value,
|
||||
std::is_same<T, U>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
bool
|
||||
>;
|
||||
|
||||
@@ -96,19 +96,28 @@ namespace boost { namespace pfr { namespace detail {
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_ostream<Char, Traits>&> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
static std::enable_if_t<
|
||||
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
std::basic_ostream<Char, Traits>&
|
||||
> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
::boost::pfr::flat_write(out, value);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_istream<Char, Traits>&> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
static std::enable_if_t<
|
||||
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
std::basic_istream<Char, Traits>&
|
||||
> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
::boost::pfr::flat_read(in, value);
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
static std::enable_if_t<
|
||||
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
std::size_t
|
||||
> hash_value(const T& value) noexcept {
|
||||
return ::boost::pfr::flat_hash<T>{}(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace detail {
|
||||
///////////////////// Helper typedef that it used by all the enable_flat_not_*_comp_t
|
||||
template <template <class, class> class Detector, class T>
|
||||
using enable_flat_not_comp_base_t = typename std::enable_if<
|
||||
not_appliable<Detector, T const&, T const&>::value && std::is_pod<T>::value,
|
||||
not_appliable<Detector, T const&, T const&>::value && std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
bool
|
||||
>::type;
|
||||
|
||||
@@ -62,13 +62,15 @@ namespace detail {
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_flat_not_ostreamable_t = typename std::enable_if<
|
||||
not_appliable<ostreamable_detector, Stream&, Type const&>::value && std::is_pod<Type>::value,
|
||||
not_appliable<ostreamable_detector, Stream&, Type const&>::value && std::is_trivial<Type>::value
|
||||
&& std::is_standard_layout<Type>::value,
|
||||
Stream&
|
||||
>::type;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_flat_not_istreamable_t = typename std::enable_if<
|
||||
not_appliable<istreamable_detector, Stream&, Type&>::value && std::is_pod<Type>::value,
|
||||
not_appliable<istreamable_detector, Stream&, Type&>::value && std::is_trivial<Type>::value
|
||||
&& std::is_standard_layout<Type>::value,
|
||||
Stream&
|
||||
>::type;
|
||||
} // namespace detail
|
||||
@@ -134,7 +136,10 @@ namespace flat_ops {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
static std::enable_if_t<
|
||||
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
std::size_t
|
||||
> hash_value(const T& value) noexcept {
|
||||
return flat_hash<T>{}(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,26 +52,26 @@
|
||||
/// std::size_t hash_value(const T& value);
|
||||
/// \endcode
|
||||
|
||||
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
|
||||
static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
|
||||
static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
|
||||
static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
|
||||
static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
|
||||
template <class Char, class Traits> \
|
||||
static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
|
||||
::boost::pfr::write(out, value); \
|
||||
return out; \
|
||||
} \
|
||||
template <class Char, class Traits> \
|
||||
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
::boost::pfr::read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
static inline std::size_t hash_value(const T& v) { \
|
||||
return ::boost::pfr::hash<T>{}(v); \
|
||||
} \
|
||||
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
|
||||
template <class Char, class Traits> \
|
||||
BOOST_PFR_MAYBE_UNUSED static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
|
||||
::boost::pfr::write(out, value); \
|
||||
return out; \
|
||||
} \
|
||||
template <class Char, class Traits> \
|
||||
BOOST_PFR_MAYBE_UNUSED static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
|
||||
::boost::pfr::read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
BOOST_PFR_MAYBE_UNUSED static inline std::size_t hash_value(const T& v) { \
|
||||
return ::boost::pfr::hash<T>{}(v); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
#endif // BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
|
||||
|
||||
@@ -241,7 +241,10 @@ template <class T> struct hash {
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
x,
|
||||
[&result](const auto& lhs) {
|
||||
result = detail::hash_impl<0, fields_count_val>::compute(lhs);
|
||||
// We can not reuse `fields_count_val` in lambda because compilers had issues with
|
||||
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
|
||||
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
result = detail::hash_impl<0, fields_count_val_lambda>::compute(lhs);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_val>{}
|
||||
);
|
||||
|
||||
@@ -94,13 +94,19 @@ namespace boost { namespace pfr { namespace detail {
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_ostream<Char, Traits>&> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
static std::enable_if_t<
|
||||
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
std::basic_ostream<Char, Traits>&
|
||||
> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
::boost::pfr::write(out, value);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::basic_istream<Char, Traits>&> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
static std::enable_if_t<
|
||||
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
||||
std::basic_istream<Char, Traits>&
|
||||
> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
::boost::pfr::read(in, value);
|
||||
return in;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace boost { namespace pfr {
|
||||
/// \endcode
|
||||
template <class Char, class Traits, class T>
|
||||
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
|
||||
out << '{';
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
detail::print_impl<0, fields_count_val>::print(out, detail::tie_as_tuple(value));
|
||||
@@ -46,7 +46,10 @@ void write(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
value,
|
||||
[&out](const auto& val) {
|
||||
detail::print_impl<0, fields_count_val>::print(out, val);
|
||||
// We can not reuse `fields_count_val` in lambda because compilers had issues with
|
||||
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
|
||||
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
|
||||
detail::print_impl<0, fields_count_val_lambda>::print(out, val);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_val>{}
|
||||
);
|
||||
@@ -70,7 +73,7 @@ void write(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
/// \endcode
|
||||
template <class Char, class Traits, class T>
|
||||
void read(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
|
||||
constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<T>();
|
||||
|
||||
const auto prev_exceptions = in.exceptions();
|
||||
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
|
||||
@@ -86,7 +89,10 @@ void read(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
::boost::pfr::detail::for_each_field_dispatcher(
|
||||
value,
|
||||
[&in](const auto& val) {
|
||||
detail::read_impl<0, fields_count_val>::read(in, val);
|
||||
// We can not reuse `fields_count_val` in lambda because compilers had issues with
|
||||
// passing constexpr variables into lambdas. Computing is again is the most portable solution.
|
||||
constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count<T>();
|
||||
detail::read_impl<0, fields_count_val_lambda>::read(in, val);
|
||||
},
|
||||
detail::make_index_sequence<fields_count_val>{}
|
||||
);
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace ops {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
static std::enable_if_t<std::is_trivial<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
return hash<T>{}(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,12 @@ PROLOGUE = """// Copyright (c) 2016-2020 Antony Polukhin
|
||||
#pragma once
|
||||
|
||||
#include <boost/pfr/detail/config.hpp>
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
# error C++17 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
#include <boost/pfr/detail/size_t_.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
@@ -65,18 +64,6 @@ 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{});
|
||||
}
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_CORE17_GENERATED_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2016-2019, Antony Polukhin.
|
||||
# Copyright (C) 2016-2020, Antony Polukhin.
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -99,13 +99,13 @@ test-suite pfr
|
||||
[ run common/non_default_constructible.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_default_constructible ]
|
||||
[ run common/non_default_constructible.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_default_constructible ]
|
||||
|
||||
[ compile-fail common/non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_copyable_but_movable ]
|
||||
[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_copyable_but_movable ]
|
||||
#[ compile-fail common/non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_copyable_but_movable ]
|
||||
#[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_copyable_but_movable ]
|
||||
[ run common/non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_copyable_but_movable ]
|
||||
[ run common/non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_copyable_but_movable ]
|
||||
|
||||
[ compile-fail common/non_default_constructible_non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_dc_non_cop_but_mov ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_dc_non_cop_but_mov ]
|
||||
#[ compile-fail common/non_default_constructible_non_copyable_but_movable.cpp : $(CLASSIC_FLAT_DEF) : flat_non_dc_non_cop_but_mov ]
|
||||
#[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_FLAT_DEF) : flat_lh_non_dc_non_cop_but_mov ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(CLASSIC_PREC_DEF) : precise_non_dc_non_cop_but_mov ]
|
||||
[ run common/non_default_constructible_non_copyable_but_movable.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_non_dc_non_cop_but_mov ]
|
||||
|
||||
@@ -143,6 +143,7 @@ test-suite pfr
|
||||
[ run precise/destructuring_tie.cpp : : : $(CLASSIC_PREC_DEF) : precise_destructuring_tie ]
|
||||
[ run precise/error_pfr_c1202.cpp : : : $(CLASSIC_PREC_DEF) : precise_c1202_issue21 ]
|
||||
[ compile-fail precise/non_aggregate.cpp : $(CLASSIC_PREC_DEF) : precise_non_aggregate ]
|
||||
[ run precise/tie_anonymous.cpp : : : $(CLASSIC_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_tie_anonymous ]
|
||||
|
||||
# See "Requirements and Limitations" section of the docs for info on following tests:
|
||||
#[ compile-fail precise/template_constructor.cpp : $(CLASSIC_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_template_constructor14 ]
|
||||
@@ -176,6 +177,7 @@ test-suite pfr
|
||||
[ run precise/issue30.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue30 ]
|
||||
[ run precise/issue33.cpp : : : $(LOOPHOLE_PREC_DEF) : precise_lh_issue33 ]
|
||||
[ compile-fail precise/non_aggregate.cpp : $(LOOPHOLE_PREC_DEF) : precise_lh_non_aggregate ]
|
||||
[ run precise/tie_anonymous.cpp : : : $(LOOPHOLE_PREC_DEF) [ requires cxx17_structured_bindings ] : precise_lh_tie_anonymous ]
|
||||
|
||||
# See "Requirements and Limitations" section of the docs for info on following tests:
|
||||
#[ compile-fail precise/template_constructor.cpp : $(LOOPHOLE_PREC_DEF) [ requires !cxx17_structured_bindings ] : precise_lh_template_constructor14 ]
|
||||
|
||||
@@ -39,10 +39,11 @@ struct comparable_struct {
|
||||
|
||||
BOOST_PFR_TEST_FUNCTIONS_FOR(comparable_struct)
|
||||
|
||||
void test_comparable_struct() {
|
||||
comparable_struct s1 {0, 1, false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, false, 6,7,8,9,10,11111};
|
||||
template <typename Struct>
|
||||
void test_some_comparable_struct() {
|
||||
Struct s1 {0, 1, false, 6,7,8,9,10,11};
|
||||
Struct s2 = s1;
|
||||
Struct s3 {0, 1, false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST_EQ(s1, s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
@@ -56,7 +57,7 @@ void test_comparable_struct() {
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
Struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
@@ -67,6 +68,10 @@ void test_comparable_struct() {
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
test_some_comparable_struct<comparable_struct>();
|
||||
}
|
||||
|
||||
struct empty { operator std::string() { return "empty{}"; } };
|
||||
BOOST_PFR_TEST_FUNCTIONS_FOR(empty)
|
||||
|
||||
@@ -105,12 +110,58 @@ void test_implicit_conversions() {
|
||||
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_TEST_FUNCTIONS_FOR
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct anonymous_comparable_struct {
|
||||
int i; short s; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
|
||||
BOOST_PFR_TEST_FUNCTIONS_FOR(anonymous_comparable_struct)
|
||||
|
||||
|
||||
struct other_anonymous_struct {
|
||||
anonymous_comparable_struct a,b;
|
||||
};
|
||||
|
||||
BOOST_PFR_TEST_FUNCTIONS_FOR(other_anonymous_struct)
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<anonymous_comparable_struct> {
|
||||
std::size_t operator()(const anonymous_comparable_struct& val) const noexcept {
|
||||
return hash_value(val);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void test_anonymous_comparable_struct() {
|
||||
test_some_comparable_struct<anonymous_comparable_struct>();
|
||||
}
|
||||
|
||||
void test_nested_anonymous_comparable_struct() {
|
||||
other_anonymous_struct s1{
|
||||
{0, 1, false, 6,7,8,9,10,11},
|
||||
{0, 1, false, 6,7,8,9,10,11},
|
||||
};
|
||||
auto s2 = s1;
|
||||
|
||||
BOOST_TEST_EQ(s1, s2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_with_contatiners<std::less<>>();
|
||||
test_with_contatiners<std::greater<>>();
|
||||
test_implicit_conversions();
|
||||
test_anonymous_comparable_struct();
|
||||
test_nested_anonymous_comparable_struct();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ int main() {
|
||||
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
|
||||
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
|
||||
#elif defined(BOOST_PFR_TEST_FLAT)
|
||||
// Test disabled in Jamfile!
|
||||
// Does not compile since GCC-10. Result is quite strange on compilers where the code compiles:
|
||||
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018 Antony Polukhin
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,10 +11,11 @@
|
||||
# error Misused test
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct X {
|
||||
X() = delete;
|
||||
X(X&&) = default;
|
||||
X(const X&) = delete;
|
||||
|
||||
@@ -23,6 +24,9 @@ struct X {
|
||||
};
|
||||
struct S { X x0; X x1; int x2; X x3; };
|
||||
|
||||
static_assert(!std::is_default_constructible<X>::value, "");
|
||||
static_assert(!std::is_default_constructible<S>::value, "");
|
||||
|
||||
int main() {
|
||||
#ifdef BOOST_PFR_TEST_PRECISE
|
||||
static_assert(boost::pfr::tuple_size_v<S> == 4, "");
|
||||
@@ -45,6 +49,8 @@ int main() {
|
||||
struct S6 { X x0; X x1; X x2; X x3; X x4; X x5;};
|
||||
static_assert(boost::pfr::tuple_size_v<S6> == 6, "");
|
||||
#elif defined(BOOST_PFR_TEST_FLAT)
|
||||
// Test disabled in Jamfile!
|
||||
// Does not compile since GCC-10. Result is quite strange on compilers where the code compiles:
|
||||
BOOST_TEST_EQ(boost::pfr::flat_tuple_size_v<S>, 1); // Empty structs are discarded
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2018 Antony Polukhin
|
||||
// Copyright (c) 2018-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -58,8 +58,8 @@ void test_counts_on_multiple_chars_impl() {
|
||||
static_assert(flat_tuple_size_v<std::conditional_t<std::is_fundamental<T1>::value, T1*, void*> > == 1, "");
|
||||
#if !defined(__GNUC__) || __GNUC__ != 8
|
||||
// GCC-8 has big problems with this test:
|
||||
// error: ‘constexpr ubiq_constructor::operator Type&() const [with Type = test_counts_on_multiple_chars()::t2*]’,
|
||||
// declared using local type ‘test_counts_on_multiple_chars()::t2’, is used but never defined [-fpermissive]
|
||||
// error: 'constexpr ubiq_constructor::operator Type&() const [with Type = test_counts_on_multiple_chars()::t2*]',
|
||||
// declared using local type 'test_counts_on_multiple_chars()::t2', is used but never defined [-fpermissive]
|
||||
//
|
||||
// Fixed in GCC-9.
|
||||
static_assert(tuple_size_v<T1*> == 1, "");
|
||||
@@ -122,7 +122,5 @@ void test_counts_on_multiple_chars() {
|
||||
|
||||
int main() {
|
||||
test_counts_on_multiple_chars< BOOST_PFR_RUN_TEST_ON >();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// requires: C++14
|
||||
#include <iostream>
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <iostream>
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ struct non_default_constructible {
|
||||
T val_;
|
||||
|
||||
non_default_constructible() = delete;
|
||||
template <class U> non_default_constructible(U&& v){}
|
||||
template <class U> non_default_constructible(U&& /*v*/){}
|
||||
};
|
||||
|
||||
struct Foo {
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// requires: C++14
|
||||
#include <iostream>
|
||||
#include "boost/pfr/precise.hpp"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "boost/pfr/precise.hpp"
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright (c) 2016-2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <iostream>
|
||||
#include "boost/pfr/precise.hpp"
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ struct optional_like {
|
||||
T val_;
|
||||
|
||||
optional_like() = default;
|
||||
template <class U> optional_like(U&& v){}
|
||||
template <class U> optional_like(U&& /*v*/){}
|
||||
};
|
||||
|
||||
struct Foo {
|
||||
|
||||
94
test/precise/tie_anonymous.cpp
Normal file
94
test/precise/tie_anonymous.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2020 Antony Polukhin
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <boost/pfr/precise/ops.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(__has_include)
|
||||
# if __has_include(<optional>)
|
||||
# include <optional>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace some {
|
||||
struct struct1{ int i; };
|
||||
struct struct2{ int i; };
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
struct anon_with_optional {
|
||||
std::string a;
|
||||
std::optional<some::struct1> b;
|
||||
std::optional<some::struct2> c;
|
||||
|
||||
};
|
||||
|
||||
struct other_anon_with_optional {
|
||||
std::string a;
|
||||
int b;
|
||||
std::optional<anon_with_optional> c;
|
||||
std::optional<some::struct2> d;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
struct other_anon {
|
||||
int data;
|
||||
};
|
||||
|
||||
struct anon {
|
||||
other_anon a;
|
||||
other_anon b;
|
||||
};
|
||||
|
||||
void test_in_anon_ns() {
|
||||
anon x{{1}, {2}};
|
||||
|
||||
auto v = boost::pfr::structure_tie(x);
|
||||
|
||||
BOOST_TEST_EQ(std::get<0>(v).data, 1);
|
||||
BOOST_TEST_EQ(std::get<1>(v).data, 2);
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
other_anon_with_optional opt{"test"};
|
||||
auto opt_val = boost::pfr::structure_tie(opt);
|
||||
BOOST_TEST_EQ(std::get<0>(opt_val), "test");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void test_in_non_non_ns() {
|
||||
anon x{{1}, {2}};
|
||||
|
||||
auto v = boost::pfr::structure_tie(x);
|
||||
|
||||
BOOST_TEST_EQ(std::get<0>(v).data, 1);
|
||||
BOOST_TEST_EQ(std::get<1>(v).data, 2);
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
other_anon_with_optional opt{"test again"};
|
||||
auto opt_val = boost::pfr::structure_tie(opt);
|
||||
BOOST_TEST_EQ(std::get<0>(opt_val), "test again");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_in_anon_ns();
|
||||
testing::test_in_non_non_ns();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user