On Sat, 6 Apr 2019 at 02:19, Ville Voutilainen <ville.voutilai...@gmail.com> wrote:
> And this patch fixes the existing visitation so that we don't > over-eagerly cast to void. The main gist of it is > > - else if constexpr (is_same_v<_Result_type, void>) > + else if constexpr (!__same_return_types && > + is_same_v<_Result_type, void>) > > and the new ensure-test is adjusted to use void as the return type of > the first visitor. ..and this patch makes cv void work as the return type. The important bits are (incrementally) - is_same_v<_Result_type, void>) + is_void_v<_Result_type>) and - return __do_visit<false, false>(std::forward<_Visitor>(__visitor), - std::forward<_Variants>(__variants)...); + return (_Res) + __do_visit<false, false>(std::forward<_Visitor>(__visitor), + std::forward<_Variants>(__variants)...); and the visit_r test is amended to also test visitation of a visitor with a const void result, when the visitor itself does not return void.
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index fdf04cf..34f3ec3 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -138,7 +138,9 @@ namespace __variant constexpr variant_alternative_t<_Np, variant<_Types...>> const&& get(const variant<_Types...>&&); - template<bool __use_index=false, typename _Visitor, typename... _Variants> + template<bool __use_index=false, + bool __same_return_types = true, + typename _Visitor, typename... _Variants> constexpr decltype(auto) __do_visit(_Visitor&& __visitor, _Variants&&... __variants); @@ -868,12 +870,15 @@ namespace __variant // tuple<V1&&, V2&&>, std::index_sequence<1, 2>> // The returned multi-dimensional vtable can be fast accessed by the visitor // using index calculation. - template<typename _Array_type, typename _Variant_tuple, typename _Index_seq> + template<bool __same_return_types, + typename _Array_type, typename _Variant_tuple, typename _Index_seq> struct __gen_vtable_impl; - template<typename _Result_type, typename _Visitor, size_t... __dimensions, + template<bool __same_return_types, + typename _Result_type, typename _Visitor, size_t... __dimensions, typename... _Variants, size_t... __indices> struct __gen_vtable_impl< + __same_return_types, _Multi_array<_Result_type (*)(_Visitor, _Variants...), __dimensions...>, tuple<_Variants...>, std::index_sequence<__indices...>> { @@ -915,10 +920,12 @@ namespace __variant if constexpr (__do_cookie) { __element = __gen_vtable_impl< + __same_return_types, _Tp, tuple<_Variants...>, std::index_sequence<__indices..., __index>>::_S_apply(); *__cookie_element = __gen_vtable_impl< + __same_return_types, _Tp, tuple<_Variants...>, std::index_sequence<__indices..., variant_npos>>::_S_apply(); @@ -926,15 +933,18 @@ namespace __variant else { __element = __gen_vtable_impl< + __same_return_types, remove_reference_t<decltype(__element)>, tuple<_Variants...>, std::index_sequence<__indices..., __index>>::_S_apply(); } } }; - template<typename _Result_type, typename _Visitor, typename... _Variants, + template<bool __same_return_types, + typename _Result_type, typename _Visitor, typename... _Variants, size_t... __indices> struct __gen_vtable_impl< + __same_return_types, _Multi_array<_Result_type (*)(_Visitor, _Variants...)>, tuple<_Variants...>, std::index_sequence<__indices...>> { @@ -952,25 +962,56 @@ namespace __variant } static constexpr decltype(auto) - __visit_invoke(_Visitor&& __visitor, _Variants... __vars) + __visit_invoke_impl(_Visitor&& __visitor, _Variants... __vars) { - if constexpr (is_same_v<_Result_type, __variant_idx_cookie>) - return std::__invoke(std::forward<_Visitor>(__visitor), + if constexpr (is_same_v<_Result_type, __variant_idx_cookie>) + return std::__invoke(std::forward<_Visitor>(__visitor), + __element_by_index_or_cookie<__indices>( + std::forward<_Variants>(__vars))..., + integral_constant<size_t, __indices>()...); + else if constexpr (!__same_return_types && + is_void_v<_Result_type>) + return (void)std::__invoke(std::forward<_Visitor>(__visitor), __element_by_index_or_cookie<__indices>( - std::forward<_Variants>(__vars))..., - integral_constant<size_t, __indices>()...); + std::forward<_Variants>(__vars))...); else return std::__invoke(std::forward<_Visitor>(__visitor), __element_by_index_or_cookie<__indices>( std::forward<_Variants>(__vars))...); } + static constexpr decltype(auto) + __do_visit_invoke(_Visitor&& __visitor, _Variants... __vars) + { + return __visit_invoke_impl(std::forward<_Visitor>(__visitor), + std::forward<_Variants>(__vars)...); + } + + static constexpr _Result_type + __do_visit_invoke_r(_Visitor&& __visitor, _Variants... __vars) + { + return __visit_invoke_impl(std::forward<_Visitor>(__visitor), + std::forward<_Variants>(__vars)...); + } + + static constexpr decltype(auto) + __visit_invoke(_Visitor&& __visitor, _Variants... __vars) + { + if constexpr (__same_return_types) + return __do_visit_invoke(std::forward<_Visitor>(__visitor), + std::forward<_Variants>(__vars)...); + else + return __do_visit_invoke_r(std::forward<_Visitor>(__visitor), + std::forward<_Variants>(__vars)...); + } + static constexpr auto _S_apply() { return _Array_type{&__visit_invoke}; } }; - template<typename _Result_type, typename _Visitor, typename... _Variants> + template<bool __same_return_types, + typename _Result_type, typename _Visitor, typename... _Variants> struct __gen_vtable { using _Func_ptr = _Result_type (*)(_Visitor&&, _Variants...); @@ -981,7 +1022,8 @@ namespace __variant static constexpr _Array_type _S_apply() { - return __gen_vtable_impl<_Array_type, tuple<_Variants...>, + return __gen_vtable_impl<__same_return_types, + _Array_type, tuple<_Variants...>, std::index_sequence<>>::_S_apply(); } @@ -1582,7 +1624,9 @@ namespace __variant std::get<0>(std::forward<_Variants>(__variants))...); } - template<bool __use_index, typename _Visitor, typename... _Variants> + template<bool __use_index, + bool __same_return_types, + typename _Visitor, typename... _Variants> constexpr decltype(auto) __do_visit(_Visitor&& __visitor, _Variants&&... __variants) { @@ -1592,6 +1636,7 @@ namespace __variant std::forward<_Variants>(__variants)...)); constexpr auto& __vtable = __detail::__variant::__gen_vtable< + __same_return_types, _Result_type, _Visitor&&, _Variants&&...>::_S_vtable; auto __func_ptr = __vtable._M_access(__variants.index()...); @@ -1618,12 +1663,10 @@ namespace __variant if ((__variants.valueless_by_exception() || ...)) __throw_bad_variant_access("Unexpected index"); - if constexpr (std::is_void_v<_Res>) - (void) __do_visit(std::forward<_Visitor>(__visitor), - std::forward<_Variants>(__variants)...); - else - return __do_visit(std::forward<_Visitor>(__visitor), - std::forward<_Variants>(__variants)...); + + return (_Res) + __do_visit<false, false>(std::forward<_Visitor>(__visitor), + std::forward<_Variants>(__variants)...); } #endif diff --git a/libstdc++-v3/testsuite/20_util/variant/visit_r.cc b/libstdc++-v3/testsuite/20_util/variant/visit_r.cc index 5eed0cf..55f5f8b 100644 --- a/libstdc++-v3/testsuite/20_util/variant/visit_r.cc +++ b/libstdc++-v3/testsuite/20_util/variant/visit_r.cc @@ -42,8 +42,22 @@ test01() static_assert(std::is_void_v<decltype(std::visit<void>(Visitor{}, v1, v2))>); } +void test02() +{ + struct Visitor + { + int operator()(double) {return 42;} + double operator()(int) {return 0.02;} + }; + std::variant<int, double> v; + std::visit<int>(Visitor(), v); + std::visit<const void>(Visitor(), v); +} + + int main() { test01(); + test02(); } diff --git a/libstdc++-v3/testsuite/20_util/variant/visit_r_neg.cc b/libstdc++-v3/testsuite/20_util/variant/visit_r_neg.cc new file mode 100644 index 0000000..ae6fdd1 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/variant/visit_r_neg.cc @@ -0,0 +1,45 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <variant> +#include <testsuite_hooks.h> + +// { dg-error "invalid conversion" "" { target *-*-* } 0 } +// { dg-prune-output "in 'constexpr' expansion" } + +void +test01() +{ + { + struct Visitor + { + double operator()(double) {return 0.02;} + void operator()(int) {} + }; + std::variant<int, double> v; + std::visit(Visitor(), v); + } +} + +int +main() +{ + test01(); +}