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

Merge pull request #119 from denzor200/fix/broken_structured_binding2

Workaround for broken C++17 stuctured binding in old compilers
This commit is contained in:
Antony Polukhin
2023-01-10 20:13:44 +03:00
committed by GitHub
4 changed files with 2173 additions and 268 deletions

View File

@@ -22,7 +22,7 @@ struct do_not_define_std_tuple_size_for_me {
template <class T>
constexpr bool do_structured_bindings_work() noexcept { // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
T val{};
const auto& [a] = val; // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
auto& [a] = val; // ******************************************* IN CASE OF ERROR READ THE FOLLOWING LINES IN boost/pfr/detail/core17.hpp FILE:
/****************************************************************************
*

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
#!/usr/bin/python
# Copyright (c) 2016-2022 Antony Polukhin
# Copyright (c) 2023 Denis Mikhailov
#
# 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)
@@ -12,8 +13,10 @@ import string
# Skipping some letters that may produce keywords or are hard to read, or shadow template parameters
ascii_letters = string.ascii_letters.replace("o", "").replace("O", "").replace("i", "").replace("I", "").replace("T", "")
WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE = 3
PROLOGUE = """// Copyright (c) 2016-2020 Antony Polukhin
PROLOGUE = """// Copyright (c) 2016-2022 Antony Polukhin
// Copyright (c) 2023 Denis Mikhailov
//
// 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)
@@ -35,6 +38,7 @@ PROLOGUE = """// Copyright (c) 2016-2020 Antony Polukhin
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/size_t_.hpp>
#include <type_traits> // for std::conditional_t, std::is_reference
namespace boost { namespace pfr { namespace detail {
@@ -43,6 +47,29 @@ constexpr auto make_tuple_of_references(Args&&... args) noexcept {
return sequence_tuple::tuple<Args&...>{ args... };
}
template<typename T, typename Arg>
constexpr decltype(auto) add_cv_like(Arg& arg) noexcept {
if constexpr (std::is_const<T>::value && std::is_volatile<T>::value) {
return const_cast<const volatile Arg&>(arg);
}
else if constexpr (std::is_const<T>::value) {
return const_cast<const Arg&>(arg);
}
else if constexpr (std::is_volatile<T>::value) {
return const_cast<volatile Arg&>(arg);
}
else {
return const_cast<Arg&>(arg);
}
}
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78939
template<typename T, typename Sb, typename Arg>
constexpr decltype(auto) workaround_cast(Arg& arg) noexcept {
using output_arg_t = std::conditional_t<!std::is_reference<Sb>(), decltype(detail::add_cv_like<T>(arg)), Sb>;
return const_cast<output_arg_t>(arg);
}
template <class T>
constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
return sequence_tuple::tuple<>{};
@@ -50,8 +77,8 @@ constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = 0) noexcept {
auto& [a] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(a);
auto& [a] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(detail::workaround_cast<T, decltype(a)>(a));
}
@@ -77,6 +104,33 @@ constexpr void tie_as_tuple(T& /*val*/, size_t_<I>) noexcept {
############################################################################################################################
def fold_workaround_cast(indexes, divider):
WORKAROUND_CAST_TEMPLATE = """
detail::workaround_cast<T, decltype({arg})>({arg})
"""
lines = []
div = ''
tokens = [x.strip() for x in indexes.split(',')]
casts = [WORKAROUND_CAST_TEMPLATE.strip().format(arg=tok)
for tok in tokens]
for i in range(0, len(casts)):
if i%WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE==0:
div = ''
lines.append('')
lines[-1] += div + casts[i]
div = ','
return divider.join(lines)
def calc_indexes_count(indexes):
tokens = [x.strip() for x in indexes.split(',')]
return len(tokens)
class EmptyLinePrinter:
def print_once(self):
if not self.printed:
print("")
self.printed = True
printed = False
indexes = " a"
print(PROLOGUE)
@@ -92,18 +146,26 @@ for i in range(1, funcs_count):
indexes += ascii_letters[i // max_args_on_a_line - 1]
indexes += ascii_letters[i % max_args_on_a_line]
printed_casts = fold_workaround_cast(indexes.strip(), ",\n ")
indexes_count = calc_indexes_count(indexes.strip())
empty_printer = EmptyLinePrinter()
print("template <class T>")
print("constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {")
if i < max_args_on_a_line:
print(" auto& [" + indexes.strip() + "] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
print(" return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");")
print(" auto& [" + indexes.strip() + "] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
else:
print(" auto& [")
print(indexes)
print(" ] = val; // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
print("")
print(" ] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
empty_printer.print_once()
if indexes_count < WORKAROUND_CAST_EXPRESSIONS_LIMIT_PER_LINE:
print(" return ::boost::pfr::detail::make_tuple_of_references(" + printed_casts + ");")
else:
empty_printer.print_once()
print(" return ::boost::pfr::detail::make_tuple_of_references(")
print(indexes)
print(" " + printed_casts)
print(" );")
print("}\n")

View File

@@ -0,0 +1,125 @@
// Copyright (c) 2023 Denis Mikhailov
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr/core.hpp>
#include <type_traits> // for std::is_same
struct A {
const volatile int cv_value = 0;
volatile int v_value = 0;
const int c_value = 0;
int value = 0;
const volatile int& cv_ref;
volatile int& v_ref;
const int& c_ref;
int& ref;
const volatile int&& cv_rref;
volatile int&& v_rref;
const int&& c_rref;
int&& rref;
};
int main() {
#if BOOST_PFR_USE_CPP17
const volatile int cv_value = 0;
volatile int v_value = 0;
const int c_value = 0;
int value = 0;
typedef boost::pfr::detail::size_t_<12> fields_count_tag;
{
A a {cv_value, v_value, c_value, value,
cv_value, v_value, c_value, value,
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
// FIXME implement rvalue references as a field support
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
}
{
const A a {cv_value, v_value, c_value, value,
cv_value, v_value, c_value, value,
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int const&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
// FIXME implement rvalue references as a field support
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
}
{
volatile A a {cv_value, v_value, c_value, value,
cv_value, v_value, c_value, value,
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
// FIXME implement rvalue references as a field support
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
}
{
const volatile A a {cv_value, v_value, c_value, value,
cv_value, v_value, c_value, value,
std::move(cv_value), std::move(v_value), std::move(c_value), std::move(value)};
const auto t = boost::pfr::detail::tie_as_tuple(a, fields_count_tag{});
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<0>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<1>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<2>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<3>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<4>(t)), int const volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<5>(t)), int volatile&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<6>(t)), int const&>());
static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<7>(t)), int&>());
// FIXME implement rvalue references as a field support
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<8>(t)), int const volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<9>(t)), int volatile&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<10>(t)), int const&&>());
// static_assert(std::is_same<decltype(boost::pfr::detail::sequence_tuple::get<11>(t)), int&&>());
}
#endif
}