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

Compare commits

..

33 Commits
1.0.0 ... 1.0.2

Author SHA1 Message Date
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
33 changed files with 416 additions and 154 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

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

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

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

View File

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

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

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

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

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