├── .gitignore ├── CMakeLists.txt ├── bin └── .gitignore ├── include ├── versatile.hpp └── versatile │ ├── aggregate_wrapper.hpp │ ├── compare.hpp │ ├── in_place.hpp │ ├── io.hpp │ ├── recursive_wrapper.hpp │ ├── type_traits.hpp │ ├── utility.hpp │ ├── variant.hpp │ ├── versatile.hpp │ └── visit.hpp └── test ├── include └── test │ ├── boost_variant.hpp │ ├── common.hpp │ ├── deep_and_hard.hpp │ ├── eggs_variant.hpp │ ├── prologue.hpp │ ├── traits.hpp │ ├── variant.hpp │ ├── versatile.hpp │ ├── visit.hpp │ └── wrappers.hpp └── src ├── boost_variant.cpp ├── eggs_variant.cpp ├── multivisit.cpp ├── test_ct_boost_variant.cpp ├── test_ct_eggs_variant.cpp ├── test_ct_variant.cpp ├── test_ct_versatile.cpp ├── traits.cpp ├── variant.cpp └── versatile.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists/ 2 | CMakeLists.txt.user 3 | CMakeFiles/ 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project("versatile") 2 | 3 | cmake_minimum_required(VERSION 3.1 FATAL_ERROR) 4 | 5 | set(CMAKE_VERBOSE_MAKEFILE ON) 6 | set(CMAKE_COLOR_MAKEFILE ON) 7 | 8 | if(NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 9 | message(FATAL_ERROR "only clang supported currently") 10 | endif() 11 | 12 | include(CheckCXXCompilerFlag) 13 | 14 | CHECK_CXX_COMPILER_FLAG("-stdlib=libc++" COMPILER_SUPPORTS_LIBCXX) 15 | if(NOT COMPILER_SUPPORTS_LIBCXX) 16 | message(FATAL_ERROR "libc++ not installed or libc++ not supported by clang++") 17 | endif() 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 19 | 20 | CHECK_CXX_COMPILER_FLAG("-std=gnu++1z" COMPILER_SUPPORTS_CXX1Z) 21 | if(NOT COMPILER_SUPPORTS_CXX1Z) 22 | message(FATAL_ERROR "Compiler does not support C++1z standard") 23 | endif() 24 | add_compile_options("-std=gnu++1z") 25 | 26 | #set(CXX_EXTENSIONS ON) 27 | #set_property(TARGET ${TARGETS} PROPERTY CXX_STANDARD 17) 28 | #set_property(TARGET ${TARGETS} PROPERTY CXX_STANDARD_REQUIRED ON) 29 | add_compile_options(-fconstexpr-steps=50000000 -ftemplate-depth=150) 30 | add_compile_options(-ftemplate-backtrace-limit=0 -fconstexpr-backtrace-limit=0 -fdiagnostics-show-template-tree) 31 | add_compile_options(-W -Weverything -Wmissing-include-dirs -Wconversion -Wmismatched-tags -Wuninitialized -Wfatal-errors -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded) 32 | add_compile_options(-Wno-gnu-anonymous-struct -Wno-nested-anon-types) 33 | add_compile_options(-ftime-report) 34 | 35 | set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -fno-inline -DDEBUG=1 -D_DEBUG=1 -D_GLIBCXX_DEBUG=1") 36 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 37 | elseif(CMAKE_BUILD_TYPE STREQUAL "Release") 38 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG=1") 39 | elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") 40 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG=1") 41 | elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") 42 | set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG=1") 43 | else() 44 | message(STATUS "Wrong build type selected, default to Debug.") 45 | set(CMAKE_BUILD_TYPE "Debug") 46 | endif() 47 | 48 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer") 49 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") 50 | 51 | include_directories("include/") 52 | include_directories("test/include/") 53 | 54 | set(HEADERS 55 | "include/versatile/type_traits.hpp" 56 | "include/versatile/in_place.hpp" 57 | "include/versatile/recursive_wrapper.hpp" 58 | "include/versatile/aggregate_wrapper.hpp" 59 | "include/versatile/visit.hpp" 60 | "include/versatile/versatile.hpp" 61 | "include/versatile/variant.hpp" 62 | "include/versatile/utility.hpp" 63 | "include/versatile/compare.hpp" 64 | "include/versatile/io.hpp" 65 | "include/versatile.hpp" 66 | 67 | "test/include/test/prologue.hpp" 68 | ) 69 | 70 | add_executable("test_traits" "test/src/traits.cpp" ${HEADERS} "test/include/test/traits.hpp") 71 | add_executable("test_versatile" "test/src/versatile.cpp" ${HEADERS} "test/include/test/common.hpp" "test/include/test/visit.hpp" "test/include/test/wrappers.hpp" "test/include/test/versatile.hpp") 72 | add_executable("test_variant" "test/src/variant.cpp" ${HEADERS} "test/include/test/common.hpp" "test/include/test/visit.hpp" "test/include/test/wrappers.hpp" "test/include/test/variant.hpp") 73 | add_executable("test_boost_variant" "test/src/boost_variant.cpp" ${HEADERS} "test/include/test/common.hpp" "test/include/test/visit.hpp" "test/include/test/boost_variant.hpp") 74 | add_executable("test_eggs_variant" "test/src/eggs_variant.cpp" ${HEADERS} "test/include/test/common.hpp" "test/include/test/visit.hpp" "test/include/test/eggs_variant.hpp") 75 | add_executable("test_multivisit" "test/src/multivisit.cpp" ${HEADERS} "test/include/test/common.hpp" "test/include/test/visit.hpp" "test/include/test/versatile.hpp" "test/include/test/variant.hpp" "test/include/test/boost_variant.hpp" "test/include/test/eggs_variant.hpp") 76 | 77 | set(TESTING_TARGETS 78 | "test_traits" 79 | "test_versatile" 80 | "test_variant" 81 | "test_boost_variant" 82 | "test_eggs_variant" 83 | "test_multivisit" 84 | ) 85 | 86 | foreach(t ${TESTING_TARGETS}) 87 | set_target_properties(${t} PROPERTIES DEBUG_POSTFIX "d") 88 | endforeach() 89 | 90 | add_executable("test_ct_versatile" "test/src/test_ct_versatile.cpp" ${HEADERS} "test/include/test/deep_and_hard.hpp") 91 | add_executable("test_ct_variant" "test/src/test_ct_variant.cpp" ${HEADERS} "test/include/test/deep_and_hard.hpp") 92 | add_executable("test_ct_eggs_variant" "test/src/test_ct_eggs_variant.cpp" ${HEADERS} "test/include/test/deep_and_hard.hpp") 93 | add_executable("test_ct_boost_variant" "test/src/test_ct_boost_variant.cpp" ${HEADERS} "test/include/test/deep_and_hard.hpp") 94 | 95 | set(TESTING_CT_TARGETS 96 | "test_ct_versatile" 97 | "test_ct_variant" 98 | "test_ct_eggs_variant" 99 | "test_ct_boost_variant" 100 | ) 101 | 102 | foreach(t ${TESTING_CT_TARGETS}) 103 | target_compile_definitions(${t} PUBLIC "-DCOLS=4" "-DROWS=4") 104 | target_compile_options(${t} PUBLIC "-ftime-report") 105 | set_target_properties(${t} PROPERTIES DEBUG_POSTFIX "d") 106 | endforeach() 107 | 108 | set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}) 109 | install(TARGETS ${TESTING_TARGETS} ${TESTING_CT_TARGETS} 110 | RUNTIME DESTINATION "bin/" 111 | ) 112 | 113 | # for f in `ls bin/test_*` ; do du -sh $f ; $f && echo -e "\e[1;32mSuccess! \e[0m$f" || echo -e "\e[1;31mFailure! \e[0m$f" ; done ; 114 | 115 | #[[ 116 | message("Your C++ compiler supports these C++ features:") 117 | foreach(i ${CMAKE_CXX_COMPILE_FEATURES}) 118 | message("${i}") 119 | endforeach() 120 | target_compile_features("test_versatile" PUBLIC ${CMAKE_CXX_COMPILE_FEATURES}) 121 | ]] 122 | 123 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /include/versatile.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | -------------------------------------------------------------------------------- /include/versatile/aggregate_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace versatile 8 | { 9 | 10 | template< typename type > 11 | struct aggregate_wrapper 12 | : type 13 | { 14 | 15 | aggregate_wrapper() = default; 16 | 17 | using type::operator =; 18 | 19 | template< typename ...arguments, 20 | bool is_noexcept = noexcept(::new (std::declval< void * >()) type{std::declval< arguments >()...}) > 21 | constexpr 22 | aggregate_wrapper(arguments &&... _arguments) noexcept(is_noexcept) 23 | : type{std::forward< arguments >(_arguments)...} 24 | { ; } 25 | 26 | }; 27 | 28 | template< typename type > 29 | struct unwrap_type< aggregate_wrapper< type > > 30 | : unwrap_type< type > 31 | { 32 | 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /include/versatile/compare.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "variant.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace versatile 9 | { 10 | 11 | struct equal_to 12 | { 13 | 14 | template< typename type > 15 | constexpr 16 | bool 17 | operator () (type const & _lhs, type const & _rhs) const 18 | { 19 | return static_cast< bool >(_lhs == _rhs); 20 | } 21 | 22 | template< typename lhs, typename rhs > 23 | bool 24 | operator () (lhs const &, rhs const &) const 25 | { 26 | throw std::bad_cast{}; 27 | } 28 | 29 | }; 30 | 31 | template< typename lhs, typename rhs > 32 | constexpr 33 | std::enable_if_t< (is_visitable_v< lhs > || is_visitable_v< rhs >), bool > 34 | operator == (lhs const & _lhs, rhs const & _rhs) 35 | { 36 | return multivisit(equal_to{}, _lhs, _rhs); 37 | } 38 | 39 | struct less 40 | { 41 | 42 | template< typename type > 43 | constexpr 44 | bool 45 | operator () (type const & _lhs, type const & _rhs) const 46 | { 47 | return static_cast< bool >(_lhs < _rhs); 48 | } 49 | 50 | template< typename lhs, typename rhs > 51 | bool 52 | operator () (lhs const &, rhs const &) const 53 | { 54 | throw std::bad_cast{}; 55 | } 56 | 57 | }; 58 | 59 | template< typename lhs, typename rhs > 60 | constexpr 61 | std::enable_if_t< (is_visitable_v< lhs > || is_visitable_v< rhs >), bool > 62 | operator < (lhs const & _lhs, rhs const & _rhs) 63 | { 64 | return multivisit(less{}, _lhs, _rhs); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /include/versatile/in_place.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace versatile 6 | { 7 | 8 | struct in_place_t {}; 9 | 10 | template< typename type = in_place_t > 11 | constexpr 12 | in_place_t 13 | in_place(type) 14 | { 15 | return {}; 16 | } 17 | 18 | template< std::size_t i > 19 | constexpr 20 | in_place_t 21 | in_place(index_t< i >) 22 | { 23 | return {}; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /include/versatile/io.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace versatile 9 | { 10 | 11 | template< typename visitable > 12 | std::enable_if_t< is_visitable_v< visitable >, std::istream & > 13 | operator >> (std::istream & _in, visitable & _visitable) 14 | { 15 | visit([&] (auto & _value) { _in >> _value; }, _visitable); 16 | return _in; 17 | } 18 | 19 | template< typename visitable > 20 | std::enable_if_t< is_visitable_v< visitable >, std::ostream & > 21 | operator << (std::ostream & _out, visitable const & _visitable) 22 | { 23 | visit([&] (auto const & _value) { _out << _value; }, _visitable); 24 | return _out; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /include/versatile/recursive_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace versatile 10 | { 11 | 12 | template< typename this_type > 13 | class recursive_wrapper 14 | { 15 | 16 | std::unique_ptr< this_type > storage_; 17 | 18 | public : 19 | 20 | template< typename ...arguments > 21 | recursive_wrapper(arguments &&... _arguments) 22 | : storage_(std::make_unique< this_type >(std::forward< arguments >(_arguments)...)) 23 | { ; } 24 | 25 | template< typename type > 26 | operator type & () noexcept 27 | { 28 | return static_cast< type & >(*storage_); 29 | } 30 | 31 | template< typename type > 32 | operator type const & () const noexcept 33 | { 34 | return static_cast< type const & >(*storage_); 35 | } 36 | 37 | void 38 | swap(recursive_wrapper & _other) noexcept 39 | { 40 | storage_.swap(_other.storage_); 41 | } 42 | 43 | }; 44 | 45 | template< typename type > 46 | struct unwrap_type< recursive_wrapper< type > > 47 | : unwrap_type< type > 48 | { 49 | 50 | }; 51 | 52 | template< typename type > 53 | struct unref_type< recursive_wrapper< type > > 54 | : unref_type< type > 55 | { 56 | 57 | }; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /include/versatile/type_traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace versatile 6 | { 7 | 8 | template< typename ...types > 9 | struct identity; 10 | 11 | template<> 12 | struct identity<> 13 | { 14 | 15 | }; 16 | 17 | template< typename first, typename ...rest > 18 | struct identity< first, rest... > 19 | { 20 | 21 | using type = first; 22 | 23 | }; 24 | 25 | template< std::size_t i > 26 | using index_t = std::integral_constant< std::size_t, i >; 27 | 28 | enum class type_qualifier 29 | { 30 | value, 31 | const_value, 32 | volatile_value, 33 | volatile_const_value, 34 | lref, 35 | rref, 36 | const_lref, 37 | const_rref, 38 | volatile_lref, 39 | volatile_rref, 40 | volatile_const_lref, 41 | volatile_const_rref, 42 | 43 | count_ 44 | }; 45 | 46 | template< type_qualifier type_qual, typename type > struct add_type_qualifier; 47 | template< typename to > struct add_type_qualifier< type_qualifier::value , to > { using type = to ; }; 48 | template< typename to > struct add_type_qualifier< type_qualifier::const_value , to > { using type = to const ; }; 49 | template< typename to > struct add_type_qualifier< type_qualifier::volatile_value , to > { using type = volatile to ; }; 50 | template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_value , to > { using type = volatile to const ; }; 51 | template< typename to > struct add_type_qualifier< type_qualifier::lref , to > { using type = to & ; }; 52 | template< typename to > struct add_type_qualifier< type_qualifier::rref , to > { using type = to &&; }; 53 | template< typename to > struct add_type_qualifier< type_qualifier::const_lref , to > { using type = to const & ; }; 54 | template< typename to > struct add_type_qualifier< type_qualifier::const_rref , to > { using type = to const &&; }; 55 | template< typename to > struct add_type_qualifier< type_qualifier::volatile_lref , to > { using type = volatile to & ; }; 56 | template< typename to > struct add_type_qualifier< type_qualifier::volatile_rref , to > { using type = volatile to &&; }; 57 | template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_lref , to > { using type = volatile to const & ; }; 58 | template< typename to > struct add_type_qualifier< type_qualifier::volatile_const_rref , to > { using type = volatile to const &&; }; 59 | 60 | template< type_qualifier type_qual, typename to > 61 | using add_type_qualifier_t = typename add_type_qualifier< type_qual, to >::type; 62 | 63 | template< typename from > constexpr type_qualifier type_qualifier_of = type_qualifier::value ; 64 | template< typename from > constexpr type_qualifier type_qualifier_of< from const > = type_qualifier::const_value ; 65 | template< typename from > constexpr type_qualifier type_qualifier_of< volatile from > = type_qualifier::volatile_value ; 66 | template< typename from > constexpr type_qualifier type_qualifier_of< volatile from const > = type_qualifier::volatile_const_value ; 67 | template< typename from > constexpr type_qualifier type_qualifier_of< from & > = type_qualifier::lref ; 68 | template< typename from > constexpr type_qualifier type_qualifier_of< from && > = type_qualifier::rref ; 69 | template< typename from > constexpr type_qualifier type_qualifier_of< from const & > = type_qualifier::const_lref ; 70 | template< typename from > constexpr type_qualifier type_qualifier_of< from const && > = type_qualifier::const_rref ; 71 | template< typename from > constexpr type_qualifier type_qualifier_of< volatile from & > = type_qualifier::volatile_lref ; 72 | template< typename from > constexpr type_qualifier type_qualifier_of< volatile from && > = type_qualifier::volatile_rref ; 73 | template< typename from > constexpr type_qualifier type_qualifier_of< volatile from const & > = type_qualifier::volatile_const_lref ; 74 | template< typename from > constexpr type_qualifier type_qualifier_of< volatile from const && > = type_qualifier::volatile_const_rref ; 75 | 76 | template< typename from, typename to > 77 | using copy_cv_reference_t = add_type_qualifier_t< type_qualifier_of< from >, to >; 78 | 79 | template< typename type, typename ...types > 80 | struct index_at // characteristic is 1-based right-to-left index of leftmost matched type if any 81 | { 82 | 83 | }; 84 | 85 | template< typename type, typename ...rest > 86 | struct index_at< type, type, rest... > 87 | : index_t< (1 + sizeof...(rest)) > 88 | { 89 | 90 | }; 91 | 92 | template< typename type, typename first, typename ...rest > 93 | struct index_at< type, first, rest... > 94 | : index_at< type, rest... > 95 | { 96 | 97 | }; 98 | 99 | template< typename type, typename ...types > 100 | using index_at_t = typename index_at< type, types... >::type; 101 | 102 | template< std::size_t i, typename ...types > 103 | struct at_index // i treated as 1-based right-to-left index 104 | { 105 | 106 | }; 107 | 108 | template< typename first, typename ...rest > 109 | struct at_index< (1 + sizeof...(rest)), first, rest... > 110 | : identity< first > 111 | { 112 | 113 | }; 114 | 115 | template< std::size_t i, typename first, typename ...rest > 116 | struct at_index< i, first, rest... > 117 | : at_index< i, rest... > 118 | { 119 | 120 | }; 121 | 122 | template< std::size_t i, typename ...types > 123 | using at_index_t = typename at_index< i, types... >::type; 124 | 125 | template< bool ...values > 126 | struct get_index; // characteristic is 1-based right-to-left index of leftmost true if any 127 | 128 | template<> 129 | struct get_index<> 130 | { 131 | 132 | }; 133 | 134 | template< bool ...rest > 135 | struct get_index< true, rest... > 136 | : index_t< (1 + sizeof...(rest)) > 137 | { 138 | 139 | }; 140 | 141 | template< bool ...rest > 142 | struct get_index< false, rest... > 143 | : get_index< rest... > 144 | { 145 | 146 | }; 147 | 148 | template< bool ...values > 149 | using get_index_t = typename get_index< values... >::type; 150 | 151 | template< typename type > 152 | struct is_visitable 153 | : std::false_type 154 | { 155 | 156 | }; 157 | 158 | template< typename type > 159 | constexpr bool is_visitable_v = is_visitable< type >::value; 160 | 161 | template< typename type > 162 | struct unref_type 163 | : identity< type > 164 | { 165 | 166 | }; 167 | 168 | template< typename type > 169 | using unref_type_t = typename unref_type< type >::type; 170 | 171 | template< typename type > 172 | struct unwrap_type 173 | : identity< type > 174 | { 175 | 176 | }; 177 | 178 | template< typename type > 179 | using unwrap_type_t = typename unwrap_type< std::decay_t< type > >::type; 180 | 181 | template< typename type, typename ...arguments > 182 | struct is_constructible // may be specialized for incomplete types wrapped in recursive_wrapper 183 | : std::is_constructible< type, arguments... > 184 | { 185 | 186 | }; 187 | 188 | template< typename type, typename ...arguments > 189 | constexpr bool is_constructible_v = is_constructible< type, arguments... >::value; 190 | 191 | } 192 | -------------------------------------------------------------------------------- /include/versatile/utility.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace versatile 9 | { 10 | 11 | template< type_qualifier type_qual, typename type, 12 | typename result_type = add_type_qualifier_t< type_qual, std::remove_reference_t< type > > > 13 | constexpr 14 | result_type // preserve const 15 | forward_as(type && _value) noexcept(noexcept(static_cast< result_type >(_value))) 16 | { 17 | return static_cast< result_type >(_value); 18 | } 19 | 20 | template< typename pattern, typename type, 21 | typename result_type = copy_cv_reference_t< pattern, std::remove_reference_t< type > > > 22 | constexpr 23 | result_type // preserve const 24 | forward_as(type && _value) noexcept(noexcept(static_cast< result_type >(_value))) 25 | { 26 | return static_cast< result_type >(_value); 27 | } 28 | 29 | template< typename type, typename visitable > 30 | constexpr 31 | bool 32 | is_active(visitable const & _visitable) noexcept 33 | { 34 | return _visitable.template active< type >(); 35 | } 36 | 37 | template< typename visitable, typename ...arguments > 38 | constexpr 39 | visitable 40 | make_variant(arguments &&... _arguments) noexcept(noexcept(::new (std::declval< void * >()) visitable{in_place<>, std::declval< arguments >()...})) 41 | { 42 | return visitable{in_place<>, std::forward< arguments >(_arguments)...}; 43 | } 44 | 45 | namespace details 46 | { 47 | 48 | template< typename visitor, typename ...visitors > 49 | struct composite_visitor 50 | : unwrap_type_t< visitor > 51 | , composite_visitor< visitors... >::type 52 | { 53 | 54 | using type = composite_visitor; 55 | 56 | using head = unwrap_type_t< visitor >; 57 | using tail = typename composite_visitor< visitors... >::type; 58 | 59 | using head::operator (); 60 | using tail::operator (); 61 | 62 | constexpr 63 | composite_visitor(visitor & _visitor, visitors &... _visitors) noexcept(noexcept(::new (std::declval< void * >()) head(std::declval< visitor >())) && noexcept(::new (std::declval< void * >()) tail{_visitors...})) 64 | : head(std::forward< visitor >(_visitor)) 65 | , tail{_visitors...} 66 | { ; } 67 | 68 | }; 69 | 70 | template< typename visitor > 71 | struct composite_visitor< visitor > 72 | { 73 | 74 | using type = unwrap_type_t< visitor >; 75 | 76 | }; 77 | 78 | } 79 | 80 | template< typename visitor, typename ...visitors, 81 | typename result_type = typename details::composite_visitor< visitor, visitors... >::type > 82 | constexpr 83 | result_type 84 | compose_visitors(visitor && _visitor, visitors &&... _visitors) noexcept(noexcept(::new (std::declval< void * >()) result_type{_visitor, _visitors...})) 85 | { 86 | return {_visitor, _visitors...}; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /include/versatile/variant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace versatile 10 | { 11 | 12 | template< typename ...types > 13 | class variant 14 | : enable_default_constructor< (is_constructible_v< types > || ...) > 15 | { 16 | 17 | using storage = versatile< types... >; 18 | 19 | // `All problems in computer science can be solved 20 | // by another level of indirection, 21 | // except for the problem of too many layers of indirection.` 22 | recursive_wrapper< storage > storage_; 23 | 24 | // Change implementation to based on the next when p0135r0 will come into effect: 25 | // versatile< recursive_wrapper< unref_type_t< types > >... > storage_; 26 | // it save a lot of heap memory 27 | 28 | public : 29 | 30 | using variant_type = variant; 31 | 32 | using types_t = identity< unwrap_type_t< types >... >; 33 | using indices_t = std::index_sequence_for< types... >; 34 | 35 | template< typename type > 36 | using index_at_t = typename storage::template index_at_t< type >; 37 | 38 | template< typename ...arguments > 39 | using index_of_constructible_t = typename storage::template index_of_constructible_t< arguments... >; 40 | 41 | std::size_t 42 | which() const noexcept 43 | { 44 | return static_cast< storage const & >(storage_).which(); 45 | } 46 | 47 | template< typename type > 48 | bool 49 | active() const noexcept 50 | { 51 | return static_cast< storage const & >(storage_).template active< type >(); 52 | } 53 | 54 | private : 55 | 56 | explicit 57 | variant(recursive_wrapper< storage > && _storage) 58 | : variant::enabler({}) 59 | , storage_(std::move(_storage)) 60 | { ; } 61 | 62 | struct constructor 63 | { 64 | 65 | template< typename type > 66 | recursive_wrapper< storage > 67 | operator () (type && _value) const 68 | { 69 | return std::forward< type >(_value); 70 | } 71 | 72 | }; 73 | 74 | public : 75 | 76 | variant() = default; 77 | 78 | variant(variant & _rhs) 79 | : variant(visit(constructor{}, _rhs.storage_)) 80 | { ; } 81 | 82 | variant(variant const & _rhs) 83 | : variant(visit(constructor{}, _rhs.storage_)) 84 | { ; } 85 | 86 | variant(variant && _rhs) 87 | : variant(visit(constructor{}, std::move(_rhs.storage_))) 88 | { ; } 89 | 90 | variant(variant const && _rhs) 91 | : variant(visit(constructor{}, std::move(_rhs.storage_))) 92 | { ; } 93 | 94 | template< std::size_t i, 95 | typename ...arguments > 96 | explicit 97 | variant(in_place_t (&)(index_t< i >), arguments &&... _arguments) 98 | : variant({in_place< i >, std::forward< arguments >(_arguments)...}) 99 | { ; } 100 | 101 | template< typename type, 102 | typename index = index_at_t< type > > 103 | variant(type && _value) 104 | : variant(in_place< index >, std::forward< type >(_value)) 105 | { ; } 106 | 107 | template< typename type, 108 | typename ...arguments, 109 | typename index = index_at_t< type > > 110 | explicit 111 | variant(in_place_t (&)(type), arguments &&... _arguments) 112 | : variant(in_place< index >, std::forward< arguments >(_arguments)...) 113 | { ; } 114 | 115 | template< typename ...arguments, 116 | typename index = index_of_constructible_t< arguments... > > 117 | explicit 118 | variant(in_place_t (&)(in_place_t), arguments &&... _arguments) 119 | : variant(in_place< index >, std::forward< arguments >(_arguments)...) 120 | { ; } 121 | 122 | template< typename ...arguments, 123 | typename = std::enable_if_t< (1 < sizeof...(arguments)) >, // experimental 124 | typename index = index_of_constructible_t< arguments... > > 125 | explicit 126 | variant(arguments &&... _arguments) 127 | : variant(in_place< index >, std::forward< arguments >(_arguments)...) 128 | { ; } 129 | 130 | void 131 | swap(variant & _other) noexcept 132 | { 133 | storage_.swap(_other.storage_); 134 | } 135 | 136 | private : 137 | 138 | struct assigner 139 | { 140 | 141 | storage & destination_; 142 | 143 | template< typename type > 144 | void 145 | operator () (type && _value) const 146 | { 147 | static_cast< unwrap_type_t< type > & >(destination_) = std::forward< type >(_value); 148 | } 149 | 150 | }; 151 | 152 | template< typename type > 153 | variant & 154 | assign(type && _rhs) 155 | { 156 | if (which() == _rhs.which()) { 157 | visit(assigner{storage_}, std::forward< type >(_rhs)); 158 | } else { 159 | variant(std::forward< type >(_rhs)).swap(*this); 160 | } 161 | return *this; 162 | } 163 | 164 | public : 165 | 166 | variant & 167 | operator = (variant & _rhs) 168 | { 169 | return assign(_rhs); 170 | } 171 | 172 | variant & 173 | operator = (variant const & _rhs) 174 | { 175 | return assign(_rhs); 176 | } 177 | 178 | variant & 179 | operator = (variant && _rhs) 180 | { 181 | return assign(std::move(_rhs)); 182 | } 183 | 184 | variant & 185 | operator = (variant const && _rhs) 186 | { 187 | return assign(std::move(_rhs)); 188 | } 189 | 190 | template< typename type, 191 | typename index = index_at_t< type > > 192 | variant & 193 | operator = (type && _value) 194 | { 195 | if (active< type >()) { 196 | static_cast< unwrap_type_t< type > & >(storage_) = std::forward< type >(_value); 197 | } else { 198 | variant(std::forward< type >(_value)).swap(*this); 199 | } 200 | return *this; 201 | } 202 | 203 | template< typename type, 204 | typename index = index_at_t< type > > 205 | explicit 206 | operator type & () 207 | { 208 | return static_cast< type & >(storage_); 209 | } 210 | 211 | template< typename type, 212 | typename index = index_at_t< type > > 213 | explicit 214 | operator type const & () const 215 | { 216 | return static_cast< type const & >(storage_); 217 | } 218 | 219 | }; 220 | 221 | template<> 222 | class variant<> 223 | { 224 | 225 | }; 226 | 227 | template< typename first, typename ...rest > 228 | struct is_visitable< variant< first, rest... > > 229 | : std::true_type 230 | { 231 | 232 | }; 233 | 234 | template< typename first, typename ...rest > 235 | void 236 | swap(variant< first, rest... > & _lhs, 237 | variant< first, rest... > & _rhs) noexcept 238 | { 239 | _lhs.swap(_rhs); 240 | } 241 | 242 | template< std::size_t i, typename ...arguments, 243 | typename first, typename ...rest > 244 | void 245 | emplace(variant< first, rest... > & _variant, arguments &&... _arguments) 246 | { 247 | variant< first, rest... >{in_place< i >, std::forward< arguments >(_arguments)...}.swap(_variant); 248 | } 249 | 250 | template< typename type = in_place_t, typename ...arguments, 251 | typename first, typename ...rest > 252 | void 253 | emplace(variant< first, rest... > & _variant, arguments &&... _arguments) 254 | { 255 | variant< first, rest... >{in_place< type >, std::forward< arguments >(_arguments)...}.swap(_variant); 256 | } 257 | 258 | } 259 | -------------------------------------------------------------------------------- /include/versatile/versatile.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace versatile 14 | { 15 | 16 | template< bool trivially_destructible, typename ...types > 17 | class constructor_dispatcher; 18 | 19 | template< bool trivially_destructible > 20 | class constructor_dispatcher< trivially_destructible > 21 | { 22 | 23 | }; 24 | 25 | template< typename first, typename ...rest > 26 | class constructor_dispatcher< true, first, rest... > 27 | { 28 | 29 | union 30 | { 31 | 32 | first head_; 33 | constructor_dispatcher< true, rest... > tail_; 34 | 35 | }; 36 | 37 | public : 38 | 39 | template< typename ...arguments > 40 | constexpr 41 | constructor_dispatcher(index_t< (1 + sizeof...(rest)) >, 42 | arguments &&... _arguments) 43 | : head_(std::forward< arguments >(_arguments)...) 44 | { ; } 45 | 46 | template< typename ...arguments > 47 | constexpr 48 | constructor_dispatcher(arguments &&... _arguments) 49 | : tail_(std::forward< arguments >(_arguments)...) 50 | { ; } 51 | 52 | using this_type = unwrap_type_t< first >; 53 | 54 | constexpr 55 | operator this_type const & () const noexcept 56 | { 57 | return head_; 58 | } 59 | 60 | constexpr 61 | operator this_type & () noexcept 62 | { 63 | return head_; 64 | } 65 | 66 | template< typename type > 67 | constexpr 68 | operator type const & () const noexcept 69 | { 70 | return tail_; 71 | } 72 | 73 | template< typename type > 74 | constexpr 75 | operator type & () noexcept 76 | { 77 | return tail_; 78 | } 79 | 80 | }; 81 | 82 | template< typename first, typename ...rest > 83 | class constructor_dispatcher< false, first, rest... > 84 | { 85 | 86 | union 87 | { 88 | 89 | first head_; 90 | constructor_dispatcher< false, rest... > tail_; 91 | 92 | }; 93 | 94 | public : 95 | 96 | constructor_dispatcher(constructor_dispatcher const &) = default; 97 | constructor_dispatcher(constructor_dispatcher &) = default; 98 | constructor_dispatcher(constructor_dispatcher &&) = default; 99 | 100 | constructor_dispatcher & operator = (constructor_dispatcher const &) = default; 101 | constructor_dispatcher & operator = (constructor_dispatcher &) = default; 102 | constructor_dispatcher & operator = (constructor_dispatcher &&) = default; 103 | 104 | ~constructor_dispatcher() noexcept 105 | { ; } 106 | 107 | template< typename ...arguments > 108 | constexpr 109 | constructor_dispatcher(index_t< (1 + sizeof...(rest)) >, 110 | arguments &&... _arguments) 111 | : head_(std::forward< arguments >(_arguments)...) 112 | { ; } 113 | 114 | template< typename ...arguments > 115 | constexpr 116 | constructor_dispatcher(arguments &&... _arguments) 117 | : tail_(std::forward< arguments >(_arguments)...) 118 | { ; } 119 | 120 | void 121 | destruct(in_place_t (&)(first)) noexcept 122 | { 123 | head_.~first(); 124 | } 125 | 126 | template< typename type > 127 | void 128 | destruct(in_place_t (&)(type)) noexcept 129 | { 130 | tail_.destruct(in_place< type >); 131 | } 132 | 133 | using this_type = unwrap_type_t< first >; 134 | 135 | constexpr 136 | operator this_type const & () const noexcept 137 | { 138 | return head_; 139 | } 140 | 141 | constexpr 142 | operator this_type & () noexcept 143 | { 144 | return head_; 145 | } 146 | 147 | template< typename type > 148 | constexpr 149 | operator type const & () const noexcept 150 | { 151 | return tail_; 152 | } 153 | 154 | template< typename type > 155 | constexpr 156 | operator type & () noexcept 157 | { 158 | return tail_; 159 | } 160 | 161 | }; 162 | 163 | template< bool trivially_destructible, typename ...types > 164 | class destructor_dispatcher; 165 | 166 | template< typename ...types > 167 | class destructor_dispatcher< true, types... > 168 | { 169 | 170 | std::size_t which_; 171 | constructor_dispatcher< true, types... > storage_; 172 | 173 | public : 174 | 175 | constexpr 176 | std::size_t 177 | which() const noexcept 178 | { 179 | return which_; 180 | } 181 | 182 | template< typename index, typename ...arguments > 183 | constexpr 184 | destructor_dispatcher(index, arguments &&... _arguments) 185 | : which_{index::value} 186 | , storage_(index{}, std::forward< arguments >(_arguments)...) 187 | { ; } 188 | 189 | template< typename type > 190 | constexpr 191 | operator type const & () const noexcept 192 | { 193 | return storage_; 194 | } 195 | 196 | template< typename type > 197 | constexpr 198 | operator type & () noexcept 199 | { 200 | return storage_; 201 | } 202 | 203 | }; 204 | 205 | template< typename ...types > 206 | class destructor_dispatcher< false, types... > 207 | { 208 | 209 | using storage = constructor_dispatcher< false, types... >; 210 | 211 | std::size_t which_; 212 | storage storage_; 213 | 214 | template< typename type > 215 | static 216 | void 217 | destruct(storage & _storage) noexcept 218 | { 219 | _storage.destruct(in_place< type >); 220 | } 221 | 222 | using destructor = decltype(&destructor_dispatcher::template destruct< typename identity< types... >::type >); 223 | 224 | static constexpr destructor destructors_[sizeof...(types)] = {destructor_dispatcher::template destruct< types >...}; 225 | 226 | public : 227 | 228 | constexpr 229 | std::size_t 230 | which() const noexcept 231 | { 232 | return which_; 233 | } 234 | 235 | destructor_dispatcher(destructor_dispatcher const &) = default; 236 | destructor_dispatcher(destructor_dispatcher &) = default; 237 | destructor_dispatcher(destructor_dispatcher &&) = default; 238 | 239 | destructor_dispatcher & operator = (destructor_dispatcher const &) = default; 240 | destructor_dispatcher & operator = (destructor_dispatcher &) = default; 241 | destructor_dispatcher & operator = (destructor_dispatcher &&) = default; 242 | 243 | ~destructor_dispatcher() noexcept 244 | { 245 | assert(!(sizeof...(types) < which_)); 246 | if (0 < which_) { 247 | destructors_[sizeof...(types) - which_](storage_); 248 | } 249 | } 250 | 251 | template< typename index, typename ...arguments > 252 | constexpr 253 | destructor_dispatcher(index, arguments &&... _arguments) 254 | : which_{index::value} 255 | , storage_(index{}, std::forward< arguments >(_arguments)...) 256 | { ; } 257 | 258 | template< typename type > 259 | constexpr 260 | operator type const & () const noexcept 261 | { 262 | return storage_; 263 | } 264 | 265 | template< typename type > 266 | constexpr 267 | operator type & () noexcept 268 | { 269 | return storage_; 270 | } 271 | 272 | }; 273 | 274 | template< typename ...types > 275 | constexpr typename destructor_dispatcher< false, types... >::destructor destructor_dispatcher< false, types... >::destructors_[sizeof...(types)]; 276 | 277 | template< bool default_constructible > 278 | struct enable_default_constructor; 279 | 280 | template<> 281 | struct enable_default_constructor< true > 282 | { 283 | 284 | using enabler = enable_default_constructor; 285 | 286 | enable_default_constructor() = default; 287 | 288 | constexpr 289 | enable_default_constructor(void *) 290 | { ; } 291 | 292 | }; 293 | 294 | template<> 295 | struct enable_default_constructor< false > 296 | { 297 | 298 | using enabler = enable_default_constructor; 299 | 300 | enable_default_constructor() = delete; 301 | 302 | constexpr 303 | enable_default_constructor(void *) 304 | { ; } 305 | 306 | }; 307 | 308 | template< typename ...types > 309 | class versatile 310 | : enable_default_constructor< (is_constructible_v< types > || ...) > 311 | { 312 | 313 | destructor_dispatcher< (std::is_trivially_destructible_v< types > && ...), types... > storage_; 314 | 315 | public : 316 | 317 | using variant_type = versatile; 318 | 319 | using types_t = identity< unwrap_type_t< types >... >; 320 | using indices_t = std::index_sequence_for< types... >; 321 | 322 | template< typename type > 323 | using index_at_t = index_at_t< unwrap_type_t< type >, unwrap_type_t< types >... >; 324 | 325 | template< typename ...arguments > 326 | using index_of_constructible_t = get_index_t< is_constructible_v< types, arguments... >... >; 327 | 328 | constexpr 329 | std::size_t 330 | which() const noexcept 331 | { 332 | return storage_.which(); 333 | } 334 | 335 | template< typename type > 336 | constexpr 337 | bool 338 | active() const noexcept 339 | { 340 | return (storage_.which() == index_at_t< type >::value); 341 | } 342 | 343 | constexpr 344 | versatile() 345 | : versatile(in_place<>) 346 | { ; } 347 | 348 | template< std::size_t i, typename ...arguments > 349 | explicit 350 | constexpr 351 | versatile(in_place_t (&)(index_t< i >), arguments &&... _arguments) 352 | : versatile::enabler({}) 353 | , storage_(index_t< i >{}, std::forward< arguments >(_arguments)...) 354 | { ; } 355 | 356 | template< typename type, 357 | typename index = index_at_t< type > > 358 | constexpr 359 | versatile(type && _value) 360 | : versatile(in_place< index >, std::forward< type >(_value)) 361 | { ; } 362 | 363 | template< typename type, typename ...arguments, 364 | typename index = index_at_t< type > > 365 | explicit 366 | constexpr 367 | versatile(in_place_t (&)(type), arguments &&... _arguments) 368 | : versatile(in_place< index >, std::forward< arguments >(_arguments)...) 369 | { ; } 370 | 371 | template< typename ...arguments, 372 | typename index = index_of_constructible_t< arguments... > > 373 | explicit 374 | constexpr 375 | versatile(in_place_t (&)(in_place_t), arguments &&... _arguments) 376 | : versatile(in_place< index >, std::forward< arguments >(_arguments)...) 377 | { ; } 378 | 379 | template< typename ...arguments, 380 | typename = std::enable_if_t< (1 < sizeof...(arguments)) >, // experimental 381 | typename index = index_of_constructible_t< arguments... > > 382 | explicit 383 | constexpr 384 | versatile(arguments &&... _arguments) 385 | : versatile(in_place< index >, std::forward< arguments >(_arguments)...) 386 | { ; } 387 | 388 | constexpr 389 | void 390 | swap(versatile & _that) noexcept(std::is_nothrow_move_assignable_v< versatile > && std::is_nothrow_move_constructible_v< versatile >) 391 | { 392 | versatile this_ = std::move(*this); 393 | *this = std::move(_that); 394 | _that = std::move(this_); 395 | } 396 | 397 | template< typename type, 398 | typename index = index_at_t< type > > 399 | constexpr 400 | versatile & 401 | operator = (type && _value) noexcept 402 | { 403 | return (*this = versatile(std::forward< type >(_value))); // http://stackoverflow.com/questions/33936295/ 404 | } 405 | 406 | template< typename type, 407 | typename index = index_at_t< type > > 408 | explicit 409 | constexpr 410 | operator type const & () const 411 | { 412 | return (active< type >() ? storage_ : throw std::bad_cast{}); 413 | } 414 | 415 | template< typename type, 416 | typename index = index_at_t< type > > 417 | explicit 418 | constexpr 419 | operator type & () 420 | { 421 | return (active< type >() ? storage_ : throw std::bad_cast{}); 422 | } 423 | 424 | }; 425 | 426 | template<> 427 | class versatile<> 428 | { 429 | 430 | }; 431 | 432 | template< typename first, typename ...rest > 433 | struct is_visitable< versatile< first, rest... > > 434 | : std::true_type 435 | { 436 | 437 | }; 438 | 439 | template< typename first, typename ...rest > 440 | constexpr 441 | void 442 | swap(versatile< first, rest... > & _lhs, 443 | versatile< first, rest... > & _rhs) noexcept(noexcept(_lhs.swap(_rhs))) 444 | { 445 | _lhs.swap(_rhs); 446 | } 447 | 448 | template< std::size_t i, typename ...arguments, typename first, typename ...rest > 449 | constexpr 450 | void 451 | emplace(versatile< first, rest... > & _versatile, arguments &&... _arguments) 452 | { 453 | _versatile = versatile< first, rest... >(in_place< i >, std::forward< arguments >(_arguments)...); 454 | } 455 | 456 | template< typename type = in_place_t, typename ...arguments, typename first, typename ...rest > 457 | constexpr 458 | void 459 | emplace(versatile< first, rest... > & _versatile, arguments &&... _arguments) 460 | { 461 | _versatile = versatile< first, rest... >(in_place< type >, std::forward< arguments >(_arguments)...); 462 | } 463 | 464 | } 465 | -------------------------------------------------------------------------------- /include/versatile/visit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace versatile 12 | { 13 | 14 | namespace details 15 | { 16 | 17 | template< type_qualifier type_qual, typename visitor, 18 | typename visitable > 19 | class dispatcher; 20 | 21 | template< type_qualifier type_qual, typename visitor, 22 | template< typename ...types > class decay_type, typename ...types > 23 | class dispatcher< type_qual, visitor, decay_type< types... > > 24 | { 25 | 26 | using visitable = add_type_qualifier_t< type_qual, decay_type< types... > >; 27 | 28 | template< typename type > 29 | using qualify_type_t = add_type_qualifier_t< type_qual, unwrap_type_t< type > >; 30 | 31 | using first = qualify_type_t< typename identity< types... >::type >; 32 | 33 | template< typename ...arguments > 34 | struct result_type // wrap to establish type-id to suppress re-deducing of result type when callee instantiated for all the types... 35 | : identity< decltype(std::declval< visitor >()(std::declval< first >(), std::declval< arguments >()...)) > 36 | { 37 | 38 | }; 39 | 40 | template< typename type, typename ...arguments > 41 | static 42 | constexpr 43 | typename result_type< arguments... >::type 44 | callee(visitor & _visitor, visitable & _visitable, arguments &... _arguments) 45 | { 46 | return std::forward< visitor >(_visitor)(static_cast< type >(static_cast< type & >(_visitable)), std::forward< arguments >(_arguments)...); 47 | } 48 | 49 | template< typename ...arguments > 50 | using callee_type = decltype(&dispatcher::template callee< first, arguments... >); 51 | 52 | template< typename ...arguments > 53 | static constexpr callee_type< arguments... > callies_[sizeof...(types)] = {dispatcher::template callee< qualify_type_t< types >, arguments... >...}; 54 | 55 | public : 56 | 57 | template< typename ...arguments > 58 | static 59 | constexpr 60 | typename result_type< arguments... >::type 61 | caller(visitor & _visitor, visitable & _visitable, arguments &... _arguments) 62 | { 63 | std::size_t const which_ = _visitable.which(); 64 | assert(!(sizeof...(types) < which_)); 65 | return (0 < which_) ? callies_< arguments... >[sizeof...(types) - which_](_visitor, _visitable, _arguments...) : throw std::bad_cast{}; 66 | } 67 | 68 | }; 69 | 70 | template< type_qualifier type_qual, typename visitor, 71 | template< typename ...types > class decay_type, typename ...types > 72 | template< typename ...arguments > 73 | constexpr typename dispatcher< type_qual, visitor, decay_type< types... > >::template callee_type< arguments... > dispatcher< type_qual, visitor, decay_type< types... > >::callies_[sizeof...(types)]; 74 | 75 | } 76 | 77 | template< typename visitor, typename visitable, typename ...arguments > 78 | constexpr 79 | decltype(auto) 80 | visit(visitor && _visitor, visitable && _visitable, arguments &&... _arguments) 81 | { 82 | using decay_type = unwrap_type_t< visitable >; 83 | static_assert(is_visitable_v< decay_type >, "second argument should be visitable"); 84 | return details::dispatcher< type_qualifier_of< visitable && >, visitor, decay_type >::template caller< arguments... >(_visitor, _visitable, _arguments...); 85 | } 86 | 87 | namespace details 88 | { 89 | 90 | template< typename supervisitor, typename type, bool = is_visitable< unwrap_type_t< type > >::value > 91 | struct subvisitor; 92 | 93 | template< typename supervisitor, typename visitable > 94 | struct subvisitor< supervisitor, visitable, true > 95 | { 96 | 97 | supervisitor & supervisitor_; 98 | visitable & visitable_; 99 | 100 | template< typename ...visited > 101 | constexpr 102 | decltype(auto) 103 | operator () (visited &&... _visited) const 104 | { 105 | return visit(std::forward< supervisitor >(supervisitor_), std::forward< visitable >(visitable_), std::forward< visited >(_visited)...); 106 | } 107 | 108 | }; 109 | 110 | template< typename supervisitor, typename type > 111 | struct subvisitor< supervisitor, type, false > 112 | { 113 | 114 | supervisitor & supervisitor_; 115 | type & value_; 116 | 117 | template< typename ...visited > 118 | constexpr 119 | decltype(auto) 120 | operator () (visited &&... _visited) const 121 | { 122 | return std::forward< supervisitor >(supervisitor_)(std::forward< type >(value_), std::forward< visited >(_visited)...); 123 | } 124 | 125 | }; 126 | 127 | template< typename ...visitables > 128 | struct visitor_partially_applier; 129 | 130 | template<> 131 | struct visitor_partially_applier<> 132 | { 133 | 134 | template< typename visitor > 135 | static 136 | constexpr 137 | decltype(auto) 138 | call(visitor & _visitor) 139 | { 140 | return std::forward< visitor >(_visitor)(); 141 | } 142 | 143 | }; 144 | 145 | template< typename first, typename ...rest > 146 | struct visitor_partially_applier< first, rest... > 147 | { 148 | 149 | template< typename visitor > 150 | static 151 | constexpr 152 | decltype(auto) 153 | call(visitor & _visitor, first & _first, rest &... _rest) 154 | { 155 | return visitor_partially_applier< rest... >::template call< subvisitor< visitor, first > const >({_visitor, _first}, _rest...); 156 | } 157 | 158 | }; 159 | 160 | } 161 | 162 | template< typename visitor, typename ...visitables > 163 | constexpr 164 | decltype(auto) 165 | multivisit(visitor && _visitor, visitables &&... _visitables) 166 | { 167 | return details::visitor_partially_applier< visitables... >::template call< visitor >(_visitor, _visitables...); 168 | } 169 | 170 | namespace details 171 | { 172 | 173 | template< typename visitor > 174 | struct delayed_visitor 175 | { 176 | 177 | constexpr 178 | delayed_visitor(visitor & _visitor) noexcept(std::is_lvalue_reference_v< visitor > || std::is_nothrow_move_constructible_v< visitor >) 179 | : visitor_(std::forward< visitor >(_visitor)) 180 | { ; } 181 | 182 | template< typename ...types > 183 | constexpr 184 | decltype(auto) 185 | operator () (types &&... _values) & 186 | { 187 | return multivisit(visitor_, std::forward< types >(_values)...); 188 | } 189 | 190 | template< typename ...types > 191 | constexpr 192 | decltype(auto) 193 | operator () (types &&... _values) const & 194 | { 195 | return multivisit(std::as_const(visitor_), std::forward< types >(_values)...); 196 | } 197 | 198 | template< typename ...types > 199 | constexpr 200 | decltype(auto) 201 | operator () (types &&... _values) && 202 | { 203 | return multivisit(std::move(visitor_), std::forward< types >(_values)...); 204 | } 205 | 206 | template< typename ...types > 207 | constexpr 208 | decltype(auto) 209 | operator () (types &&... _values) const && 210 | { 211 | return multivisit(std::move(std::as_const(visitor_)), std::forward< types >(_values)...); 212 | } 213 | 214 | private : 215 | 216 | visitor visitor_; 217 | 218 | }; 219 | 220 | } 221 | 222 | template< typename visitor > 223 | constexpr 224 | details::delayed_visitor< visitor > 225 | visit(visitor && _visitor) noexcept(std::is_lvalue_reference_v< visitor > || std::is_nothrow_move_constructible_v< visitor >) 226 | { 227 | return _visitor; 228 | } 229 | 230 | template< typename visitable, typename ...arguments > 231 | constexpr // lambda is not constexpr yet 232 | decltype(auto) 233 | invoke(visitable && _visitable, arguments &&... _arguments) 234 | { 235 | return visit([&] (auto && _value) -> decltype(auto) 236 | { 237 | return std::forward< decltype(_value) >(_value)(std::forward< arguments >(_arguments)...); 238 | }, std::forward< visitable >(_visitable)); 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /test/include/test/boost_variant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "test/prologue.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace test_boost_variant 14 | { 15 | 16 | using ::boost::get; 17 | using ::versatile::index_at_t; 18 | using ::versatile::get_index; 19 | using ::versatile::unwrap_type_t; 20 | 21 | template< typename ...types > 22 | class boost_variant_c // composition 23 | { 24 | 25 | using variant = ::boost::variant< types... >; 26 | 27 | variant storage_; 28 | 29 | public : 30 | 31 | template< typename type > 32 | using index_at_t = index_at_t< unwrap_type_t< type >, unwrap_type_t< types >... >; 33 | 34 | template< typename ...arguments > 35 | using index_of_constructible = get_index< std::is_constructible_v< types, arguments... >... >; 36 | 37 | boost_variant_c() = default; 38 | 39 | boost_variant_c(boost_variant_c const &) = default; 40 | boost_variant_c(boost_variant_c &) = default; 41 | boost_variant_c(boost_variant_c &&) = default; 42 | 43 | boost_variant_c & operator = (boost_variant_c const &) = default; 44 | boost_variant_c & operator = (boost_variant_c &) = default; 45 | boost_variant_c & operator = (boost_variant_c &&) = default; 46 | 47 | template< typename type, typename = index_at_t< type > > 48 | boost_variant_c(type && _value) 49 | : storage_(std::forward< type >(_value)) 50 | { ; } 51 | 52 | template< typename type, typename = index_at_t< type > > 53 | boost_variant_c & 54 | operator = (type && _value) 55 | { 56 | storage_ = std::forward< type >(_value); 57 | return *this; 58 | } 59 | 60 | std::size_t 61 | which() const 62 | { 63 | return sizeof...(types) - static_cast< std::size_t >(storage_.which()); 64 | } 65 | 66 | template< typename type > 67 | bool 68 | active() const noexcept 69 | { 70 | return (index_at_t< type >::value == which()); 71 | } 72 | 73 | template< typename type, typename = index_at_t< type > > 74 | explicit 75 | operator type const & () const 76 | { 77 | if (!active< type >()) { 78 | throw std::bad_cast{}; 79 | } 80 | return get< type >(storage_); 81 | } 82 | 83 | template< typename type, typename = index_at_t< type > > 84 | explicit 85 | operator type & () 86 | { 87 | if (!active< type >()) { 88 | throw std::bad_cast{}; 89 | } 90 | return get< type >(storage_); 91 | } 92 | 93 | }; 94 | 95 | template< typename type, typename ...types > 96 | CONSTEXPRF 97 | bool 98 | is_active(boost_variant_c< types... > const & v) noexcept 99 | { 100 | return v.template active< type >(); 101 | } 102 | 103 | template< typename ...types > 104 | class boost_variant_i // inheritance 105 | : private ::boost::variant< types... > 106 | { 107 | 108 | using base = ::boost::variant< types... >; 109 | 110 | public : 111 | 112 | template< typename type > 113 | using index_at_t = index_at_t< unwrap_type_t< type >, unwrap_type_t< types >... >; 114 | 115 | template< typename ...arguments > 116 | using index_of_constructible = get_index< std::is_constructible_v< types, arguments... >... >; 117 | 118 | //using base::base; // seems there is wrong design of boost::variant constructor 119 | //using base::operator =; 120 | 121 | boost_variant_i() = default; 122 | 123 | boost_variant_i(boost_variant_i const &) = default; 124 | boost_variant_i(boost_variant_i &) = default; 125 | boost_variant_i(boost_variant_i &&) = default; 126 | 127 | boost_variant_i & operator = (boost_variant_i const &) = default; 128 | boost_variant_i & operator = (boost_variant_i &) = default; 129 | boost_variant_i & operator = (boost_variant_i &&) = default; 130 | 131 | template< typename type, typename = index_at_t< type > > 132 | boost_variant_i(type && _value) 133 | : base(std::forward< type >(_value)) 134 | { ; } 135 | 136 | template< typename type, typename = index_at_t< type > > 137 | boost_variant_i & 138 | operator = (type && _value) 139 | { 140 | base::operator = (std::forward< type >(_value)); 141 | return *this; 142 | } 143 | 144 | std::size_t 145 | which() const 146 | { 147 | return sizeof...(types) - static_cast< std::size_t >(base::which()); 148 | } 149 | 150 | template< typename type > 151 | bool 152 | active() const noexcept 153 | { 154 | return (index_at_t< type >::value == which()); 155 | } 156 | 157 | template< typename type, typename = index_at_t< type > > 158 | explicit 159 | operator type const & () const 160 | { 161 | if (!active< type >()) { 162 | throw std::bad_cast{}; 163 | } 164 | return get< type >(static_cast< base const & >(*this)); 165 | } 166 | 167 | template< typename type, typename = index_at_t< type > > 168 | explicit 169 | operator type & () 170 | { 171 | if (!active< type >()) { 172 | throw std::bad_cast{}; 173 | } 174 | return get< type >(static_cast< base & >(*this)); 175 | } 176 | 177 | }; 178 | 179 | template< typename type, typename ...types > 180 | CONSTEXPRF 181 | bool 182 | is_active(boost_variant_i< types... > const & v) noexcept 183 | { 184 | return v.template active< type >(); 185 | } 186 | 187 | template< typename type > 188 | struct boost_recursive_wrapper 189 | : ::versatile::identity< ::boost::recursive_wrapper< type > > 190 | { 191 | 192 | }; 193 | 194 | } // namespace test_boost_variant 195 | 196 | namespace versatile 197 | { 198 | 199 | template< typename type > 200 | struct unwrap_type< ::boost::recursive_wrapper< type > > 201 | : unwrap_type< type > 202 | { 203 | 204 | }; 205 | 206 | template< typename first, typename ...rest > 207 | struct is_visitable< ::test_boost_variant::boost_variant_i< first, rest... > > 208 | : std::true_type 209 | { 210 | 211 | }; 212 | 213 | template< typename first, typename ...rest > 214 | struct is_visitable< ::test_boost_variant::boost_variant_c< first, rest... > > 215 | : std::true_type 216 | { 217 | 218 | }; 219 | 220 | } // namespace versatile 221 | -------------------------------------------------------------------------------- /test/include/test/common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test/prologue.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace test 11 | { 12 | 13 | using ::versatile::is_active; 14 | 15 | template< template< typename ... > class wrapper, 16 | template< typename ... > class visitable > 17 | class check_indexing 18 | { 19 | 20 | template< typename ...types > 21 | using V = visitable< typename wrapper< types >::type... >; 22 | 23 | template< typename > 24 | struct check_indexing_; 25 | 26 | template< std::size_t ...i > 27 | struct check_indexing_< std::index_sequence< i... > > 28 | { 29 | 30 | template< std::size_t = 0 > 31 | struct S 32 | { 33 | 34 | }; 35 | 36 | using U = V< S< i >... >; 37 | 38 | SA(((U::template index_at_t< S< i > >::value == (sizeof...(i) - i)) && ...)); 39 | SA(((U::template index_of_constructible_t< S< i > >::value == (sizeof...(i) - i)) && ...)); 40 | 41 | template< std::size_t = 0 > 42 | struct N 43 | { 44 | 45 | N() = delete; 46 | 47 | }; 48 | 49 | template< std::size_t j > 50 | using W = V< std::conditional_t< (i < j), N< i >, S< i > >... >; 51 | 52 | SA(((W< i >::template index_of_constructible_t<>::value == (sizeof...(i) - i)) && ...)); 53 | 54 | CONSTEXPRF 55 | static 56 | bool 57 | run() noexcept 58 | { 59 | CHECK ((is_active< S< i > >(U{S< i >{}}) && ...)); 60 | CHECK (((U{S< i >{}}.which() == (sizeof...(i) - i)) && ...)); 61 | CHECK ((is_active< S< i > >(W< i >{}) && ...)); 62 | CHECK (((W< i >{}.which() == (sizeof...(i) - i)) && ...)); 63 | return true; 64 | } 65 | 66 | }; 67 | 68 | public : 69 | 70 | CONSTEXPRF 71 | static 72 | bool 73 | run() noexcept 74 | { 75 | CHECK (check_indexing_< std::make_index_sequence< 1 > >::run()); 76 | CHECK (check_indexing_< std::make_index_sequence< 2 > >::run()); 77 | CHECK (check_indexing_< std::make_index_sequence< 5 > >::run()); 78 | return true; 79 | } 80 | 81 | }; 82 | 83 | template< template< typename ... > class wrapper, 84 | template< typename ... > class visitable > 85 | class check_destructible 86 | { 87 | 88 | template< typename ...types > 89 | using V = visitable< typename wrapper< types >::type... >; 90 | 91 | enum class state 92 | { 93 | never_used = 0, 94 | default_constructed, 95 | copy_constructed, 96 | vcopy_constructed, 97 | move_constructed, 98 | cmove_constructed, 99 | copy_assigned, 100 | vcopy_assigned, 101 | move_assigned, 102 | cmove_assigned, 103 | moved_from, 104 | destructed, 105 | }; 106 | 107 | SA(state::never_used == state{}); 108 | 109 | static 110 | bool 111 | destructible() noexcept 112 | { 113 | using ::versatile::in_place; 114 | struct A 115 | { 116 | state s_; 117 | A() : s_{state::default_constructed} { ; } 118 | A(A const &) { s_ = state::copy_constructed; } 119 | A(A &) { s_ = state::vcopy_constructed; } 120 | A(A && a) { s_ = state::move_constructed; a.s_ = state::moved_from; } 121 | A & operator = (A const &) { s_ = state::copy_assigned; return *this; } 122 | A & operator = (A &) { s_ = state::vcopy_assigned; return *this; } 123 | A & operator = (A && a) { s_ = state::move_assigned; a.s_ = state::moved_from; return *this; } 124 | std::type_info const * * d_; 125 | void set(std::type_info const * & _d) { CHECK(!_d); d_ = &_d; } 126 | ~A() { if (!!d_) *d_ = &typeid(A); } 127 | }; 128 | struct B 129 | { 130 | state s_; 131 | B() : s_{state::default_constructed} { ; } 132 | B(B const &) { s_ = state::copy_constructed; } 133 | B(B &) { s_ = state::vcopy_constructed; } 134 | B(B && a) { s_ = state::move_constructed; a.s_ = state::moved_from; } 135 | B & operator = (B const &) { s_ = state::copy_assigned; return *this; } 136 | B & operator = (B &) { s_ = state::vcopy_assigned; return *this; } 137 | B & operator = (B && a) { s_ = state::move_assigned; a.s_ = state::moved_from; return *this; } 138 | std::type_info const * * d_; 139 | void set(std::type_info const * & _d) { CHECK(!_d); d_ = &_d; } 140 | ~B() { if (!!d_) *d_ = &typeid(B); } 141 | }; 142 | { 143 | using U = V< A, B >; 144 | { 145 | std::type_info const * d = nullptr; 146 | { 147 | U u{}; 148 | CHECK (is_active< A >(u)); 149 | CHECK (static_cast< A & >(u).s_ == state::default_constructed); 150 | static_cast< A & >(u).set(d); 151 | CHECK (!d); 152 | } 153 | CHECK (!!d); 154 | CHECK (*d == typeid(A)); 155 | } 156 | { 157 | std::type_info const * d = nullptr; 158 | { 159 | U u{in_place< B >}; 160 | CHECK (is_active< B >(u)); 161 | CHECK (static_cast< B & >(u).s_ == state::default_constructed); 162 | static_cast< B & >(u).set(d); 163 | CHECK (!d); 164 | } 165 | CHECK (!!d); 166 | CHECK (*d == typeid(B)); 167 | } 168 | { 169 | std::type_info const * d = nullptr; 170 | { 171 | U u{in_place< A >}; 172 | CHECK (is_active< A >(u)); 173 | CHECK (static_cast< A & >(u).s_ == state::default_constructed); 174 | static_cast< A & >(u).set(d); 175 | CHECK (!d); 176 | } 177 | CHECK (!!d); 178 | CHECK (*d == typeid(A)); 179 | } 180 | } 181 | return true; 182 | } 183 | 184 | public : 185 | 186 | static 187 | bool 188 | run() noexcept 189 | { 190 | CHECK (destructible()); 191 | return true; 192 | } 193 | 194 | }; 195 | 196 | template< template< typename ... > class visitable > 197 | class check_runtime 198 | { 199 | 200 | template< typename incomplete_type > 201 | using W = ::versatile::recursive_wrapper< incomplete_type >; 202 | 203 | static 204 | bool 205 | recursive() noexcept 206 | { 207 | { // composition 208 | struct R; 209 | struct A {}; 210 | using U = visitable< A, W< R > >; 211 | struct R { U v; }; 212 | U v{}; 213 | CHECK (is_active< A >(v)); 214 | v = R{}; 215 | CHECK (is_active< R >(v)); 216 | } 217 | { // composition 218 | struct R; 219 | struct A {}; 220 | using U = visitable< W< R >, A >; 221 | struct R { U v; }; 222 | U v{A{}}; 223 | CHECK (is_active< A >(v)); 224 | v = R{{A{}}}; 225 | CHECK (is_active< R >(v)); 226 | } 227 | { // inheritance 228 | struct R; 229 | struct A {}; 230 | using U = visitable< A, W< R > >; 231 | struct R : U { using U::U; using U::operator =; }; 232 | U v{}; 233 | CHECK (is_active< A >(v)); 234 | v = R{}; 235 | CHECK (is_active< R >(v)); 236 | } 237 | { // inheritance 238 | struct R; 239 | struct A {}; 240 | using U = visitable< W< R >, A >; 241 | struct R : U { using U::U; using U::operator =; }; 242 | U v{A{}}; 243 | CHECK (is_active< A >(v)); 244 | v = R{A{}}; 245 | CHECK (is_active< R >(v)); 246 | } 247 | return true; 248 | } 249 | 250 | public : 251 | 252 | static 253 | bool 254 | run() noexcept 255 | { 256 | CHECK (recursive()); 257 | return true; 258 | } 259 | 260 | }; 261 | 262 | } // namespace test 263 | -------------------------------------------------------------------------------- /test/include/test/deep_and_hard.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test/prologue.hpp" 4 | 5 | #include 6 | 7 | #include 8 | 9 | #ifndef COLS 10 | #define COLS 4 11 | #endif 12 | 13 | #ifndef ROWS 14 | #define ROWS COLS 15 | #endif 16 | 17 | namespace test 18 | { 19 | 20 | template< std::size_t > 21 | struct T 22 | { 23 | 24 | }; 25 | 26 | template< std::size_t N > 27 | struct visitor 28 | : ::boost::static_visitor< std::array< std::size_t, N > > 29 | { 30 | 31 | template< std::size_t ...I > 32 | typename visitor::result_type 33 | operator () (T< I >...) const noexcept 34 | { 35 | return {{{I}...}}; 36 | } 37 | 38 | }; 39 | 40 | 41 | template< std::size_t ...M, std::size_t ...N > 42 | bool 43 | hard(std::index_sequence< M... >, std::index_sequence< N... >) noexcept; 44 | 45 | template< std::size_t M, std::size_t N = M > 46 | bool 47 | run() noexcept 48 | { 49 | return hard(std::make_index_sequence< M >{}, std::make_index_sequence< N >{}); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /test/include/test/eggs_variant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "test/prologue.hpp" 8 | 9 | namespace test_eggs_variant 10 | { 11 | 12 | using ::versatile::index_t; 13 | using ::versatile::index_at_t; 14 | using ::versatile::get_index_t; 15 | using ::versatile::unwrap_type_t; 16 | using ::versatile::in_place; 17 | using ::versatile::in_place_t; 18 | 19 | template< typename ...types > 20 | class eggs_variant_c // composition 21 | { 22 | 23 | ::eggs::variant< types... > storage_; 24 | 25 | public : 26 | 27 | template< typename type > 28 | using index_at_t = index_at_t< unwrap_type_t< type >, unwrap_type_t< types >... >; 29 | 30 | template< typename ...arguments > 31 | using index_of_constructible_t = get_index_t< std::is_constructible_v< types, arguments... >... >; 32 | 33 | eggs_variant_c(eggs_variant_c const &) = default; 34 | eggs_variant_c(eggs_variant_c &) = default; 35 | eggs_variant_c(eggs_variant_c &&) = default; 36 | 37 | eggs_variant_c & operator = (eggs_variant_c const &) = default; 38 | eggs_variant_c & operator = (eggs_variant_c &) = default; 39 | eggs_variant_c & operator = (eggs_variant_c &&) = default; 40 | 41 | constexpr 42 | eggs_variant_c() 43 | : eggs_variant_c(in_place<>) 44 | { ; } 45 | 46 | template< std::size_t i, typename ...arguments > 47 | explicit 48 | constexpr 49 | eggs_variant_c(in_place_t (&)(index_t< i >), arguments &&... _arguments) 50 | : storage_(::eggs::variants::in_place< (sizeof...(types) - i) >, std::forward< arguments >(_arguments)...) 51 | { ; } 52 | 53 | template< typename type, typename index = index_at_t< type > > 54 | constexpr 55 | eggs_variant_c(type && _value) 56 | : eggs_variant_c(in_place< index >, std::forward< type >(_value)) 57 | { ; } 58 | 59 | template< typename type, typename index = index_at_t< type >, typename ...arguments > 60 | explicit 61 | constexpr 62 | eggs_variant_c(in_place_t (&)(type), arguments &&... _arguments) 63 | : eggs_variant_c(in_place< index >, std::forward< arguments >(_arguments)...) 64 | { ; } 65 | 66 | template< typename ...arguments, typename index = index_of_constructible_t< arguments... > > 67 | explicit 68 | constexpr 69 | eggs_variant_c(in_place_t (&)(in_place_t), arguments &&... _arguments) 70 | : eggs_variant_c(in_place< index >, std::forward< arguments >(_arguments)...) 71 | { ; } 72 | 73 | template< typename type, typename = index_at_t< type > > 74 | constexpr 75 | eggs_variant_c & 76 | operator = (type && _value) 77 | { 78 | storage_ = std::forward< type >(_value); 79 | return *this; 80 | } 81 | 82 | constexpr 83 | std::size_t 84 | which() const 85 | { 86 | if (!storage_) { 87 | return 0; 88 | } 89 | return sizeof...(types) - storage_.which(); 90 | } 91 | 92 | template< typename type > 93 | constexpr 94 | bool 95 | active() const noexcept 96 | { 97 | return (index_at_t< type >::value == which()); 98 | } 99 | 100 | template< typename type, typename = index_at_t< type > > 101 | explicit 102 | constexpr 103 | operator type const & () const 104 | { 105 | if (!active< type >()) { 106 | throw std::bad_cast{}; 107 | } 108 | return *storage_.template target< type >(); 109 | } 110 | 111 | template< typename type, typename = index_at_t< type > > 112 | explicit 113 | constexpr 114 | operator type & () 115 | { 116 | if (!active< type >()) { 117 | throw std::bad_cast{}; 118 | } 119 | return *storage_.template target< type >(); 120 | } 121 | 122 | }; 123 | 124 | } // namespace test 125 | 126 | namespace versatile 127 | { 128 | 129 | template< typename first, typename ...rest > 130 | struct is_visitable< ::test_eggs_variant::eggs_variant_c< first, rest... > > 131 | : std::true_type 132 | { 133 | 134 | }; 135 | 136 | } // namespace versatile 137 | -------------------------------------------------------------------------------- /test/include/test/prologue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #if defined(DEBUG) || defined(_DEBUG) 7 | #include 8 | #include 9 | #endif 10 | 11 | #ifdef NDEBUG 12 | #undef NDEBUG 13 | #endif 14 | #include 15 | 16 | #define STR(S) #S 17 | // double expansion of macro argument 18 | #define DEFER(D,...) D(__VA_ARGS__) 19 | #define LOCATION "file '" __FILE__ "', line: " DEFER(STR,__LINE__) 20 | #define SA(...) static_assert((__VA_ARGS__), LOCATION) 21 | #define CHECK(...) { assert((__VA_ARGS__)); } 22 | 23 | #if 1 24 | #define ASSERT(...) { SA(__VA_ARGS__); } 25 | #define CONSTEXPR constexpr 26 | #define CONSTEXPRF constexpr 27 | #define DESTRUCTOR = default; 28 | //#define CBRA { struct _ { static constexpr bool call() noexcept { 29 | //#define CKET return true; } }; SA(_::call()); } 30 | #else 31 | #define ASSERT(...) { assert((__VA_ARGS__)); } 32 | #define CONSTEXPR const 33 | #define CONSTEXPRF 34 | #define DESTRUCTOR { ; } 35 | //#define CBRA { 36 | //#define CKET } 37 | #endif 38 | 39 | namespace test 40 | { 41 | 42 | template< typename type > 43 | constexpr bool is_vcopy_constructible_v = std::is_constructible_v< type, type & >; 44 | 45 | template< typename type > 46 | constexpr bool is_cmove_constructible_v = std::is_constructible_v< type, type const && >; 47 | 48 | template< typename type > 49 | constexpr bool is_vcopy_assignable_v = std::is_assignable_v< type &, type & >; 50 | 51 | template< typename type > 52 | constexpr bool is_cmove_assignable_v = std::is_assignable_v< type &, type const && >; 53 | 54 | template< typename type > 55 | constexpr bool is_trivially_vcopy_constructible_v = std::is_trivially_constructible_v< type, type & >; 56 | 57 | template< typename type > 58 | constexpr bool is_trivially_cmove_constructible_v = std::is_trivially_constructible_v< type, type const && >; 59 | 60 | template< typename type > 61 | constexpr bool is_trivially_vcopy_assignable_v = std::is_trivially_assignable_v< type &, type & >; 62 | 63 | template< typename type > 64 | constexpr bool is_trivially_cmove_assignable_v = std::is_trivially_assignable_v< type &, type const && >; 65 | 66 | template< typename from, typename to > 67 | constexpr bool is_convertible_v = std::is_convertible< from, to >::value; 68 | 69 | template< typename from, typename to > 70 | struct is_explicitly_convertible // akrzemi1's answer http://stackoverflow.com/a/16894048/1430927 71 | : std::bool_constant< (std::is_constructible_v< to, from > && !is_convertible_v< from, to >) > 72 | { 73 | 74 | }; 75 | 76 | template< typename from, typename to > 77 | constexpr bool is_explicitly_convertible_v = is_explicitly_convertible< from, to >::value; 78 | 79 | template< std::size_t i = 0 > 80 | class literal_type 81 | { 82 | 83 | std::size_t state; 84 | 85 | public : 86 | 87 | CONSTEXPRF 88 | std::size_t 89 | get_state() const 90 | { 91 | CHECK(i == state); 92 | return state; 93 | } 94 | 95 | CONSTEXPRF literal_type(std::size_t const _state) : state(_state) { CHECK(i == _state); } 96 | literal_type() = default; 97 | 98 | }; 99 | 100 | SA(std::is_literal_type_v< literal_type<> >); 101 | SA(std::is_trivial_v< literal_type<> >); 102 | 103 | template< std::size_t i = 0 > 104 | class common_type 105 | { 106 | 107 | std::size_t state; 108 | 109 | public : 110 | 111 | CONSTEXPRF 112 | std::size_t 113 | get_state() const 114 | { 115 | CHECK(i == state); 116 | return state; 117 | } 118 | 119 | common_type(std::size_t const _state) : state(_state) { CHECK(i == _state); } 120 | common_type() { ; } 121 | common_type(common_type const & _rhs) : state(_rhs.state) { ; } 122 | common_type(common_type & _rhs) : state(_rhs.state) { ; } 123 | common_type(common_type && _rhs) : state(_rhs.state) { ; } 124 | common_type & operator = (common_type const & _rhs) { state = _rhs.state; return *this; } 125 | common_type & operator = (common_type & _rhs) { state = _rhs.state; return *this; } 126 | common_type & operator = (common_type && _rhs) { state = _rhs.state; return *this; } 127 | ~common_type() { state = ~std::size_t{}; } 128 | 129 | }; 130 | 131 | SA(!std::is_literal_type_v< common_type<> >); 132 | SA(!std::is_trivially_default_constructible_v< common_type<> >); 133 | SA(!std::is_trivially_destructible_v< common_type<> >); 134 | SA(!std::is_trivially_copy_constructible_v< common_type<> >); 135 | SA(!is_trivially_vcopy_constructible_v< common_type<> >); 136 | SA(!std::is_trivially_move_constructible_v< common_type<> >); 137 | SA(!std::is_trivially_copy_assignable_v< common_type<> >); 138 | SA(!is_trivially_vcopy_assignable_v< common_type<> >); 139 | SA(!std::is_trivially_move_assignable_v< common_type<> >); 140 | SA(std::is_default_constructible_v< common_type<> >); 141 | SA(std::is_destructible_v< common_type<> >); 142 | SA(std::is_copy_constructible_v< common_type<> >); 143 | SA(is_vcopy_constructible_v< common_type<> >); 144 | SA(std::is_move_constructible_v< common_type<> >); 145 | SA(std::is_copy_assignable_v< common_type<> >); 146 | SA(is_vcopy_assignable_v< common_type<> >); 147 | SA(std::is_move_assignable_v< common_type<> >); 148 | 149 | } // namespace test 150 | -------------------------------------------------------------------------------- /test/include/test/traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test/prologue.hpp" 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace test_traits 10 | { 11 | 12 | struct A {}; 13 | struct B {}; 14 | 15 | using ::versatile::copy_cv_reference_t; 16 | 17 | SA(std::is_same_v< copy_cv_reference_t< A , B >, B >); 18 | SA(std::is_same_v< copy_cv_reference_t< A const , B >, B const >); 19 | SA(std::is_same_v< copy_cv_reference_t< volatile A , B >, volatile B >); 20 | SA(std::is_same_v< copy_cv_reference_t< volatile A const , B >, volatile B const >); 21 | SA(std::is_same_v< copy_cv_reference_t< A &, B >, B & >); 22 | SA(std::is_same_v< copy_cv_reference_t< A const &, B >, B const & >); 23 | SA(std::is_same_v< copy_cv_reference_t< volatile A &, B >, volatile B & >); 24 | SA(std::is_same_v< copy_cv_reference_t< volatile A const &, B >, volatile B const & >); 25 | SA(std::is_same_v< copy_cv_reference_t< A &&, B >, B && >); 26 | SA(std::is_same_v< copy_cv_reference_t< A const &&, B >, B const && >); 27 | SA(std::is_same_v< copy_cv_reference_t< volatile A &&, B >, volatile B && >); 28 | SA(std::is_same_v< copy_cv_reference_t< volatile A const &&, B >, volatile B const && >); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /test/include/test/variant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test/prologue.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace test 12 | { 13 | 14 | using ::versatile::is_active; 15 | 16 | template< template< typename ... > class wrapper, 17 | template< typename ... > class variant > 18 | class check_common 19 | { 20 | 21 | template< typename ...types > 22 | using V = variant< typename wrapper< types >::type... >; 23 | 24 | static 25 | bool 26 | default_constructible() noexcept 27 | { 28 | struct S 29 | { 30 | S() = default; 31 | S(S const &) { ; } 32 | S(S &) { ; } 33 | S(S const &&) { ; } 34 | S(S &&) { ; } 35 | S & operator = (S const &) { return *this; } 36 | S & operator = (S &) { return *this; } 37 | S & operator = (S const &&) { return *this; } 38 | S & operator = (S &&) { return *this; } 39 | //~S() DESTRUCTOR 40 | }; 41 | SA(std::is_default_constructible_v< S >); 42 | struct N {}; 43 | SA(std::is_default_constructible_v< N >); 44 | { 45 | using U = V< S, N >; 46 | SA(std::is_default_constructible_v< U >); 47 | { 48 | U const v{}; 49 | CHECK (is_active< S >(v)); 50 | } 51 | { 52 | U v{}; 53 | CHECK (is_active< S >(v)); 54 | } 55 | } 56 | { 57 | using U = V< N, S >; 58 | SA(std::is_default_constructible_v< U >); 59 | { 60 | U const v{}; 61 | CHECK (is_active< N >(v)); 62 | } 63 | { 64 | U v{}; 65 | CHECK (is_active< N >(v)); 66 | } 67 | } 68 | return true; 69 | } 70 | 71 | static 72 | bool 73 | copy_move_constructible() noexcept 74 | { 75 | struct S 76 | { 77 | S() { ; } 78 | S(S const &) = default; 79 | S(S &) = default; 80 | //S(S const &&) { ; } 81 | S(S &&) = default; 82 | S & operator = (S const &) { return *this; } 83 | S & operator = (S &) { return *this; } 84 | //S & operator = (S const &&) { return *this; } 85 | S & operator = (S &&) { return *this; } 86 | ~S() = default; 87 | }; 88 | SA(std::is_copy_constructible_v< S >); 89 | SA(is_vcopy_constructible_v< S > ); 90 | SA(std::is_move_constructible_v< S >); 91 | SA(is_cmove_constructible_v< S > ); 92 | struct N {}; 93 | SA(std::is_trivial_v< N >); 94 | { 95 | using U = variant< S, N >; 96 | SA(std::is_copy_constructible_v< U >); 97 | SA(is_vcopy_constructible_v< U >); 98 | SA(std::is_move_constructible_v< U >); 99 | SA(is_cmove_constructible_v< U >); 100 | { 101 | U const v{N{}}; 102 | CHECK (is_active< N >(v)); 103 | U const w{v}; 104 | CHECK (is_active< N >(w)); 105 | } 106 | { 107 | U const v{S{}}; 108 | CHECK (is_active< S >(v)); 109 | U const w{v}; 110 | CHECK (is_active< S >(w)); 111 | } 112 | { 113 | U v{N{}}; 114 | CHECK (is_active< N >(v)); 115 | U const w{v}; 116 | CHECK (is_active< N >(w)); 117 | } 118 | { 119 | U v{S{}}; 120 | CHECK (is_active< S >(v)); 121 | U const w{v}; 122 | CHECK (is_active< S >(w)); 123 | } 124 | { 125 | U const v{N{}}; 126 | CHECK (is_active< N >(v)); 127 | U const w{std::move(v)}; 128 | CHECK (is_active< N >(w)); 129 | } 130 | { 131 | U const v{S{}}; 132 | CHECK (is_active< S >(v)); 133 | U const w{std::move(v)}; 134 | CHECK (is_active< S >(w)); 135 | } 136 | { 137 | U v{N{}}; 138 | CHECK (is_active< N >(v)); 139 | U const w{std::move(v)}; 140 | CHECK (is_active< N >(w)); 141 | } 142 | { 143 | U v{S{}}; 144 | CHECK (is_active< S >(v)); 145 | U const w{std::move(v)}; 146 | CHECK (is_active< S >(w)); 147 | } 148 | } 149 | { 150 | using U = variant< N, S >; 151 | SA(std::is_copy_constructible_v< U >); 152 | SA(is_vcopy_constructible_v< U >); 153 | SA(std::is_move_constructible_v< U >); 154 | SA(is_cmove_constructible_v< U >); 155 | { 156 | U const v{N{}}; 157 | CHECK (is_active< N >(v)); 158 | U const w{v}; 159 | CHECK (is_active< N >(w)); 160 | } 161 | { 162 | U const v{S{}}; 163 | CHECK (is_active< S >(v)); 164 | U const w{v}; 165 | CHECK (is_active< S >(w)); 166 | } 167 | { 168 | U v{N{}}; 169 | CHECK (is_active< N >(v)); 170 | U const w{v}; 171 | CHECK (is_active< N >(w)); 172 | } 173 | { 174 | U v{S{}}; 175 | CHECK (is_active< S >(v)); 176 | U const w{v}; 177 | CHECK (is_active< S >(w)); 178 | } 179 | { 180 | U const v{N{}}; 181 | CHECK (is_active< N >(v)); 182 | U const w{std::move(v)}; 183 | CHECK (is_active< N >(w)); 184 | } 185 | { 186 | U const v{S{}}; 187 | CHECK (is_active< S >(v)); 188 | U const w{std::move(v)}; 189 | CHECK (is_active< S >(w)); 190 | } 191 | { 192 | U v{N{}}; 193 | CHECK (is_active< N >(v)); 194 | U const w{std::move(v)}; 195 | CHECK (is_active< N >(w)); 196 | } 197 | { 198 | U v{S{}}; 199 | CHECK (is_active< S >(v)); 200 | U const w{std::move(v)}; 201 | CHECK (is_active< S >(w)); 202 | } 203 | } 204 | return true; 205 | } 206 | 207 | static 208 | bool 209 | copy_move_assignable() noexcept 210 | { 211 | struct S 212 | { 213 | S() { ; } 214 | S(S const &) = default; 215 | S(S &) = default; 216 | //S(S const &&) { ; } 217 | S(S &&) = default; 218 | S & operator = (S const &) = default; 219 | S & operator = (S &) = default; 220 | //S & operator = (S const &&) { return *this; } 221 | S & operator = (S &&) = default; 222 | //~S() DESTRUCTOR // clang bug: if destructor is user-declared and defaulted, then defaulted assignment operators become non-trivial and marked as non-constexpr 223 | }; 224 | SA(std::is_copy_assignable_v< S >); 225 | SA(is_vcopy_assignable_v< S > ); 226 | SA(std::is_move_assignable_v< S >); 227 | SA(is_cmove_assignable_v< S > ); 228 | struct N {}; 229 | SA(std::is_trivial_v< N >); 230 | { 231 | using U = variant< S, N >; 232 | SA(std::is_copy_assignable_v< U >); 233 | SA(is_vcopy_assignable_v< U >); 234 | SA(std::is_move_assignable_v< U >); 235 | SA(is_cmove_assignable_v< U >); 236 | { 237 | U const v{N{}}; 238 | CHECK (is_active< N >(v)); 239 | U w{}; 240 | CHECK (is_active< S >(w)); 241 | w = v; 242 | CHECK (is_active< N >(w)); 243 | } 244 | { 245 | U const v{S{}}; 246 | CHECK (is_active< S >(v)); 247 | U w{}; 248 | CHECK (is_active< S >(w)); 249 | w = v; 250 | CHECK (is_active< S >(w)); 251 | } 252 | { 253 | U v{N{}}; 254 | CHECK (is_active< N >(v)); 255 | U w{}; 256 | CHECK (is_active< S >(w)); 257 | w = v; 258 | CHECK (is_active< N >(w)); 259 | } 260 | { 261 | U v{S{}}; 262 | CHECK (is_active< S >(v)); 263 | U w{}; 264 | CHECK (is_active< S >(w)); 265 | w = v; 266 | CHECK (is_active< S >(w)); 267 | } 268 | { 269 | U const v{N{}}; 270 | CHECK (is_active< N >(v)); 271 | U w{}; 272 | CHECK (is_active< S >(w)); 273 | w = std::move(v); 274 | CHECK (is_active< N >(w)); 275 | } 276 | { 277 | U const v{S{}}; 278 | CHECK (is_active< S >(v)); 279 | U w{}; 280 | CHECK (is_active< S >(w)); 281 | w = std::move(v); 282 | CHECK (is_active< S >(w)); 283 | } 284 | { 285 | U v{N{}}; 286 | CHECK (is_active< N >(v)); 287 | U w{}; 288 | CHECK (is_active< S >(w)); 289 | w = std::move(v); 290 | CHECK (is_active< N >(w)); 291 | } 292 | { 293 | U v{S{}}; 294 | CHECK (is_active< S >(v)); 295 | U w{}; 296 | CHECK (is_active< S >(w)); 297 | w = std::move(v); 298 | CHECK (is_active< S >(w)); 299 | } 300 | } 301 | { 302 | using U = variant< N, S >; 303 | SA(std::is_copy_assignable_v< U >); 304 | SA(is_vcopy_assignable_v< U >); 305 | SA(std::is_move_assignable_v< U >); 306 | SA(is_cmove_assignable_v< U >); 307 | { 308 | U const v{N{}}; 309 | CHECK (is_active< N >(v)); 310 | U w{}; 311 | CHECK (is_active< N >(w)); 312 | w = v; 313 | CHECK (is_active< N >(w)); 314 | } 315 | { 316 | U const v{S{}}; 317 | CHECK (is_active< S >(v)); 318 | U w{}; 319 | CHECK (is_active< N >(w)); 320 | w = v; 321 | CHECK (is_active< S >(w)); 322 | } 323 | { 324 | U v{N{}}; 325 | CHECK (is_active< N >(v)); 326 | U w{}; 327 | CHECK (is_active< N >(w)); 328 | w = v; 329 | CHECK (is_active< N >(w)); 330 | } 331 | { 332 | U v{S{}}; 333 | CHECK (is_active< S >(v)); 334 | U w{}; 335 | CHECK (is_active< N >(w)); 336 | w = v; 337 | CHECK (is_active< S >(w)); 338 | } 339 | { 340 | U const v{N{}}; 341 | CHECK (is_active< N >(v)); 342 | U w{}; 343 | CHECK (is_active< N >(w)); 344 | w = std::move(v); 345 | CHECK (is_active< N >(w)); 346 | } 347 | { 348 | U const v{S{}}; 349 | CHECK (is_active< S >(v)); 350 | U w{}; 351 | CHECK (is_active< N >(w)); 352 | w = std::move(v); 353 | CHECK (is_active< S >(w)); 354 | } 355 | { 356 | U v{N{}}; 357 | CHECK (is_active< N >(v)); 358 | U w{}; 359 | CHECK (is_active< N >(w)); 360 | w = std::move(v); 361 | CHECK (is_active< N >(w)); 362 | } 363 | { 364 | U v{S{}}; 365 | CHECK (is_active< S >(v)); 366 | U w{}; 367 | CHECK (is_active< N >(w)); 368 | w = std::move(v); 369 | CHECK (is_active< S >(w)); 370 | } 371 | } 372 | return true; 373 | } 374 | 375 | enum class state 376 | { 377 | never_used = 0, 378 | default_constructed, 379 | copy_constructed, 380 | vcopy_constructed, 381 | move_constructed, 382 | cmove_constructed, 383 | copy_assigned, 384 | vcopy_assigned, 385 | move_assigned, 386 | cmove_assigned, 387 | moved_from, 388 | }; 389 | 390 | SA(state::never_used == state{}); 391 | 392 | struct S 393 | { 394 | state state_ = state::never_used; 395 | S() : state_{state::default_constructed} { ; } 396 | S(S const &) : state_{state::copy_constructed} { ; } 397 | S(S &) : state_{state::vcopy_constructed} { ; } 398 | //S(S const &&) { state_ = state::cmove_constructed; } 399 | S(S && s) : state_{state::move_constructed} { s.state_ = state::moved_from; } 400 | S & operator = (S const &) { state_ = state::copy_assigned; return *this; } 401 | S & operator = (S &) { state_ = state::vcopy_assigned; return *this; } 402 | //S & operator = (S const &&) { state_ = state::cmove_assigned; return *this; } 403 | S & operator = (S && s) { state_ = state::move_assigned; s.state_ = state::moved_from; return *this; } 404 | ~S() DESTRUCTOR 405 | }; 406 | 407 | static 408 | bool 409 | convertible() noexcept 410 | { 411 | SA(std::is_copy_constructible_v< S >); 412 | SA(is_vcopy_constructible_v< S > ); 413 | SA(std::is_move_constructible_v< S >); 414 | SA(is_cmove_constructible_v< S > ); 415 | SA(std::is_copy_assignable_v< S > ); 416 | SA(is_vcopy_assignable_v< S > ); 417 | SA(std::is_move_assignable_v< S > ); 418 | SA(is_cmove_assignable_v< S > ); 419 | { 420 | using U = variant< S >; 421 | SA(std::is_copy_constructible_v< U >); 422 | SA(is_vcopy_constructible_v< U >); 423 | SA(std::is_move_constructible_v< U >); 424 | SA(is_cmove_constructible_v< U >); 425 | SA(std::is_copy_assignable_v< U >); 426 | SA(is_vcopy_assignable_v< U >); 427 | SA(std::is_move_assignable_v< U >); 428 | SA(is_cmove_assignable_v< U >); 429 | SA(is_explicitly_convertible_v< U, S >); 430 | SA(is_explicitly_convertible_v< U const, S >); 431 | SA(is_explicitly_convertible_v< U &, S >); 432 | SA(is_explicitly_convertible_v< U const &, S >); 433 | { 434 | struct T {}; 435 | SA(!is_explicitly_convertible_v< U, T >); // SFINAE-disabled conversions 436 | SA(!is_explicitly_convertible_v< U const, T >); // SFINAE-disabled conversions 437 | SA(!is_explicitly_convertible_v< U &, T >); // SFINAE-disabled conversions 438 | SA(!is_explicitly_convertible_v< U const &, T >); // SFINAE-disabled conversions 439 | } 440 | { 441 | U const v{}; 442 | CHECK (is_active< S >(v)); 443 | CHECK (static_cast< S const & >(v).state_ == state::default_constructed); 444 | S const s{v}; 445 | CHECK (static_cast< S const & >(v).state_ == state::default_constructed); 446 | CHECK (s.state_ == state::copy_constructed); 447 | } 448 | { 449 | U v{}; 450 | CHECK (is_active< S >(v)); 451 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 452 | S const s{v}; 453 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 454 | CHECK (s.state_ == state::vcopy_constructed); 455 | } 456 | { 457 | U const v{}; 458 | CHECK (is_active< S >(v)); 459 | CHECK (static_cast< S const & >(v).state_ == state::default_constructed); 460 | S const l{std::move(v)}; 461 | CHECK (static_cast< S const & >(v).state_ == state::default_constructed); 462 | CHECK (l.state_ == state::copy_constructed); // only lvalue-reference conversion operator currently is available 463 | S const r = std::move(static_cast< S const & >(v)); 464 | CHECK (static_cast< S const & >(v).state_ == state::default_constructed); 465 | CHECK (r.state_ == state::copy_constructed); // `const &` operator win 466 | } 467 | { 468 | U v{}; 469 | CHECK (is_active< S >(v)); 470 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 471 | S const l{std::move(v)}; 472 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 473 | CHECK (l.state_ == state::vcopy_constructed); // only lvalue-reference to const conversion operator currently is available 474 | S const r = std::move(static_cast< S & >(v)); 475 | CHECK (static_cast< S & >(v).state_ == state::moved_from); 476 | CHECK (r.state_ == state::move_constructed); 477 | } 478 | } 479 | return true; 480 | } 481 | 482 | static 483 | bool 484 | constructible() noexcept 485 | { 486 | SA(std::is_copy_constructible_v< S >); 487 | SA(is_vcopy_constructible_v< S > ); 488 | SA(std::is_move_constructible_v< S >); 489 | SA(is_cmove_constructible_v< S > ); 490 | SA(std::is_copy_assignable_v< S > ); 491 | SA(is_vcopy_assignable_v< S > ); 492 | SA(std::is_move_assignable_v< S > ); 493 | SA(is_cmove_assignable_v< S > ); 494 | struct N {}; 495 | SA(std::is_trivial_v< N >); 496 | { 497 | using U = variant< S, N >; 498 | SA(std::is_copy_constructible_v< U >); 499 | SA(is_vcopy_constructible_v< U >); 500 | SA(std::is_move_constructible_v< U >); 501 | SA(is_cmove_constructible_v< U >); 502 | SA(std::is_copy_assignable_v< U >); 503 | SA(is_vcopy_assignable_v< U >); 504 | SA(std::is_move_assignable_v< U >); 505 | SA(is_cmove_assignable_v< U >); 506 | { 507 | S const s{}; 508 | CHECK (s.state_ == state::default_constructed); 509 | U const v{s}; 510 | CHECK (is_active< S >(v)); 511 | CHECK (static_cast< S const & >(v).state_ == state::copy_constructed); 512 | CHECK (s.state_ == state::default_constructed); 513 | } 514 | { 515 | S s; 516 | CHECK (s.state_ == state::default_constructed); 517 | U v{s}; 518 | CHECK (is_active< S >(v)); 519 | CHECK (static_cast< S & >(v).state_ == state::vcopy_constructed); 520 | CHECK (s.state_ == state::default_constructed); 521 | } 522 | { 523 | S const s{}; 524 | CHECK (s.state_ == state::default_constructed); 525 | U const v{std::move(s)}; 526 | CHECK (is_active< S >(v)); 527 | CHECK (static_cast< S const & >(v).state_ == state::copy_constructed); // `const &` operator win 528 | CHECK (s.state_ == state::default_constructed); 529 | } 530 | { 531 | S s; 532 | CHECK (s.state_ == state::default_constructed); 533 | U v{std::move(s)}; 534 | CHECK (is_active< S >(v)); 535 | CHECK (static_cast< S & >(v).state_ == state::move_constructed); 536 | CHECK (s.state_ == state::moved_from); 537 | } 538 | } 539 | { 540 | using U = variant< N, S >; 541 | SA(std::is_copy_constructible_v< U >); 542 | SA(is_vcopy_constructible_v< U >); 543 | SA(std::is_move_constructible_v< U >); 544 | SA(is_cmove_constructible_v< U >); 545 | SA(std::is_copy_assignable_v< U >); 546 | SA(is_vcopy_assignable_v< U >); 547 | SA(std::is_move_assignable_v< U >); 548 | SA(is_cmove_assignable_v< U >); 549 | { 550 | S const s{}; 551 | CHECK (s.state_ == state::default_constructed); 552 | U const v{s}; 553 | CHECK (is_active< S >(v)); 554 | CHECK (static_cast< S const & >(v).state_ == state::copy_constructed); 555 | CHECK (s.state_ == state::default_constructed); 556 | } 557 | { 558 | S s; 559 | CHECK (s.state_ == state::default_constructed); 560 | U v{s}; 561 | CHECK (is_active< S >(v)); 562 | CHECK (static_cast< S & >(v).state_ == state::vcopy_constructed); 563 | CHECK (s.state_ == state::default_constructed); 564 | } 565 | { 566 | S const s{}; 567 | CHECK (s.state_ == state::default_constructed); 568 | U const v{std::move(s)}; 569 | CHECK (is_active< S >(v)); 570 | CHECK (static_cast< S const & >(v).state_ == state::copy_constructed); // `const &` operator win 571 | CHECK (s.state_ == state::default_constructed); 572 | } 573 | { 574 | S s; 575 | CHECK (s.state_ == state::default_constructed); 576 | U v{std::move(s)}; 577 | CHECK (is_active< S >(v)); 578 | CHECK (static_cast< S & >(v).state_ == state::move_constructed); 579 | CHECK (s.state_ == state::moved_from); 580 | } 581 | } 582 | return true; 583 | } 584 | 585 | static 586 | bool 587 | assignable() noexcept 588 | { 589 | SA(std::is_copy_constructible_v< S >); 590 | SA(is_vcopy_constructible_v< S > ); 591 | SA(std::is_move_constructible_v< S >); 592 | SA(is_cmove_constructible_v< S > ); 593 | SA(std::is_copy_assignable_v< S > ); 594 | SA(is_vcopy_assignable_v< S > ); 595 | SA(std::is_move_assignable_v< S > ); 596 | SA(is_cmove_assignable_v< S > ); 597 | struct N {}; 598 | SA(std::is_trivial_v< N >); 599 | { 600 | using U = variant< S, N >; 601 | SA(std::is_copy_constructible_v< U >); 602 | SA(is_vcopy_constructible_v< U >); 603 | SA(std::is_move_constructible_v< U >); 604 | SA(is_cmove_constructible_v< U >); 605 | SA(std::is_copy_assignable_v< U >); 606 | SA(is_vcopy_assignable_v< U >); 607 | SA(std::is_move_assignable_v< U >); 608 | SA(is_cmove_assignable_v< U >); 609 | { 610 | S const s{}; 611 | CHECK (s.state_ == state::default_constructed); 612 | U v{}; 613 | CHECK (is_active< S >(v)); 614 | v = s; 615 | CHECK (is_active< S >(v)); 616 | CHECK (static_cast< S & >(v).state_ == state::copy_assigned); 617 | CHECK (s.state_ == state::default_constructed); 618 | } 619 | { 620 | S s; 621 | CHECK (s.state_ == state::default_constructed); 622 | U v{}; 623 | CHECK (is_active< S >(v)); 624 | v = s; 625 | CHECK (is_active< S >(v)); 626 | CHECK (static_cast< S & >(v).state_ == state::vcopy_assigned); 627 | CHECK (s.state_ == state::default_constructed); 628 | } 629 | { 630 | S const s{}; 631 | CHECK (s.state_ == state::default_constructed); 632 | U v{}; 633 | CHECK (is_active< S >(v)); 634 | v = std::move(s); 635 | CHECK (is_active< S >(v)); 636 | CHECK (static_cast< S & >(v).state_ == state::copy_assigned); 637 | CHECK (s.state_ == state::default_constructed); 638 | } 639 | { 640 | S s; 641 | CHECK (s.state_ == state::default_constructed); 642 | U v{}; 643 | CHECK (is_active< S >(v)); 644 | v = std::move(s); 645 | CHECK (is_active< S >(v)); 646 | CHECK (static_cast< S & >(v).state_ == state::move_assigned); 647 | CHECK (s.state_ == state::moved_from); 648 | } 649 | } 650 | { 651 | using U = variant< N, S >; 652 | SA(std::is_copy_constructible_v< U >); 653 | SA(is_vcopy_constructible_v< U >); 654 | SA(std::is_move_constructible_v< U >); 655 | SA(is_cmove_constructible_v< U >); 656 | SA(std::is_copy_assignable_v< U >); 657 | SA(is_vcopy_assignable_v< U >); 658 | SA(std::is_move_assignable_v< U >); 659 | SA(is_cmove_assignable_v< U >); 660 | { 661 | S const s{}; 662 | CHECK (s.state_ == state::default_constructed); 663 | U v{}; 664 | CHECK (is_active< N >(v)); 665 | v = s; 666 | CHECK (is_active< S >(v)); 667 | CHECK (static_cast< S & >(v).state_ == state::copy_constructed); 668 | CHECK (s.state_ == state::default_constructed); 669 | } 670 | { 671 | S s; 672 | CHECK (s.state_ == state::default_constructed); 673 | U v{}; 674 | CHECK (is_active< N >(v)); 675 | v = s; 676 | CHECK (is_active< S >(v)); 677 | CHECK (static_cast< S & >(v).state_ == state::vcopy_constructed); 678 | CHECK (s.state_ == state::default_constructed); 679 | } 680 | { 681 | S const s{}; 682 | CHECK (s.state_ == state::default_constructed); 683 | U v{}; 684 | CHECK (is_active< N >(v)); 685 | v = std::move(s); 686 | CHECK (is_active< S >(v)); 687 | CHECK (static_cast< S & >(v).state_ == state::copy_constructed); // `const &` operator win 688 | CHECK (s.state_ == state::default_constructed); 689 | } 690 | { 691 | S s; 692 | CHECK (s.state_ == state::default_constructed); 693 | U v{}; 694 | CHECK (is_active< N >(v)); 695 | v = std::move(s); 696 | CHECK (is_active< S >(v)); 697 | CHECK (static_cast< S & >(v).state_ == state::move_constructed); 698 | CHECK (s.state_ == state::moved_from); 699 | } 700 | } 701 | return true; 702 | } 703 | 704 | static 705 | bool 706 | in_place_constructible() noexcept 707 | { 708 | using ::versatile::in_place; 709 | using ::versatile::make_variant; 710 | struct X {}; 711 | struct Y {}; 712 | { 713 | struct A {}; 714 | struct B {}; 715 | using U = V< A, B >; 716 | U const a{in_place< A >}; 717 | CHECK (is_active< A >(a)); 718 | U const b{in_place< B >}; 719 | CHECK (is_active< B >(b)); 720 | auto const d = make_variant< U >(); 721 | CHECK (is_active< A >(d)); 722 | } 723 | { 724 | struct A { A() = delete; }; 725 | struct B {}; 726 | using U = V< A, B >; 727 | U const b{in_place< B >}; 728 | CHECK (is_active< B >(b)); 729 | auto const d = make_variant< U >(); 730 | CHECK (is_active< B >(d)); 731 | } 732 | { 733 | struct A { A(X) { ; } }; 734 | struct B { B(Y) { ; } }; 735 | using U = V< A, B >; 736 | U const a{in_place< A >, X{}}; 737 | CHECK (is_active< A >(a)); 738 | U const b{in_place< B >, Y{}}; 739 | CHECK (is_active< B >(b)); 740 | auto const x = make_variant< U >(X{}); 741 | CHECK (is_active< A >(x)); 742 | auto const y = make_variant< U >(Y{}); 743 | CHECK (is_active< B >(y)); 744 | } 745 | { 746 | struct A { A(X) { ; } }; 747 | struct B { B(X) { ; } }; 748 | using U = V< A, B >; 749 | U const a{in_place< A >, X{}}; 750 | CHECK (is_active< A >(a)); 751 | U const b{in_place< B >, X{}}; 752 | CHECK (is_active< B >(b)); 753 | auto const x = make_variant< U >(X{}); 754 | CHECK (is_active< A >(x)); 755 | } 756 | { 757 | struct B; 758 | struct A { A() = default; A(B &&) { ; } }; 759 | struct B { B() = default; B(A) { ; } }; 760 | using U = V< A, B >; 761 | U const a{in_place< A >, B{}}; 762 | CHECK (is_active< A >(a)); 763 | U const b{in_place< B >, A{}}; 764 | CHECK (is_active< B >(b)); 765 | auto const x = make_variant< U >(B{}); 766 | CHECK (is_active< A >(x)); 767 | auto const y = make_variant< U >(A{}); 768 | CHECK (is_active< A >(y)); // move-constructed 769 | } 770 | { 771 | struct A { A(X, Y) { ; } }; 772 | struct B { B(Y, X) { ; } }; 773 | using U = V< A, B >; 774 | U const a{in_place< A >, X{}, Y{}}; 775 | CHECK (is_active< A >(a)); 776 | U const b{in_place< B >, Y{}, X{}}; 777 | CHECK (is_active< B >(b)); 778 | auto const x = make_variant< U >(X{}, Y{}); 779 | CHECK (is_active< A >(x)); 780 | auto const y = make_variant< U >(Y{}, X{}); 781 | CHECK (is_active< B >(y)); 782 | } 783 | return true; 784 | } 785 | 786 | static 787 | bool 788 | emplace() noexcept 789 | { 790 | using ::versatile::emplace; 791 | struct X {}; 792 | struct Y {}; 793 | struct Z {}; 794 | { 795 | struct A { A(X) { ; } }; 796 | struct B { B(Y) { ; } }; 797 | using U = V< Z, A, B >; 798 | U v{}; 799 | CHECK (is_active< Z >(v)); 800 | emplace< A >(v, X{}); 801 | CHECK (is_active< A >(v)); 802 | emplace< B >(v, Y{}); 803 | CHECK (is_active< B >(v)); 804 | emplace< Z >(v); 805 | CHECK (is_active< Z >(v)); 806 | } 807 | { 808 | struct A { A(X) { ; } }; 809 | struct B { B(X) { ; } }; 810 | using U = V< Z, A, B >; 811 | U v{}; 812 | CHECK (is_active< Z >(v)); 813 | emplace< A >(v, X{}); 814 | CHECK (is_active< A >(v)); 815 | emplace< B >(v, X{}); 816 | CHECK (is_active< B >(v)); 817 | emplace< Z >(v); 818 | CHECK (is_active< Z >(v)); 819 | } 820 | { 821 | struct B; 822 | struct A { A() = default; A(B &&) { ; } }; 823 | struct B { B() = default; B(A) { ; } }; 824 | using U = V< Z, A, B >; 825 | U v{}; 826 | CHECK (is_active< Z >(v)); 827 | emplace< A >(v, B{}); 828 | CHECK (is_active< A >(v)); 829 | emplace< B >(v, A{}); 830 | CHECK (is_active< B >(v)); 831 | emplace< Z >(v); 832 | CHECK (is_active< Z >(v)); 833 | } 834 | { 835 | struct A { A(X, Y) { ; } }; 836 | struct B { B(Y, X) { ; } }; 837 | using U = V< Z, A, B >; 838 | U v{}; 839 | CHECK (is_active< Z >(v)); 840 | emplace< A >(v, X{}, Y{}); 841 | CHECK (is_active< A >(v)); 842 | emplace< B >(v, Y{}, X{}); 843 | CHECK (is_active< B >(v)); 844 | emplace< Z >(v); 845 | CHECK (is_active< Z >(v)); 846 | } 847 | return true; 848 | } 849 | 850 | public : 851 | 852 | static 853 | bool 854 | run() noexcept 855 | { 856 | CHECK (default_constructible()); 857 | CHECK (copy_move_constructible()); 858 | CHECK (copy_move_assignable()); 859 | CHECK (convertible()); // conversion 860 | CHECK (constructible()); // conversion 861 | CHECK (assignable()); // conversion 862 | CHECK (in_place_constructible()); 863 | CHECK (emplace()); 864 | return true; 865 | } 866 | 867 | }; 868 | 869 | } // namespace test 870 | -------------------------------------------------------------------------------- /test/include/test/versatile.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test/prologue.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace test 16 | { 17 | 18 | using ::versatile::is_active; 19 | 20 | template< template< typename ... > class wrapper, 21 | template< typename ... > class versatile > 22 | class check_invariants 23 | { 24 | 25 | template< typename ...types > 26 | using V = versatile< typename wrapper< types >::type... >; 27 | 28 | struct trivial 29 | { 30 | 31 | struct S 32 | { 33 | 34 | int i; 35 | S(int j) : i(j) { ; } 36 | 37 | S() = default; 38 | 39 | S(S const &) = default; 40 | //S(S &) = default; // ?sould not be user-declared to be trivial 41 | //S(S const &&) { ; } // ?sould not be user-declared/provided to be trivial 42 | S(S &&) = default; 43 | 44 | S & operator = (S const &) = default; 45 | //S & operator = (S &) = default; // ?sould not be user-declared to be trivial 46 | //S & operator = (S const &&) { return *this; } // ?sould not be user-declared/provided to be trivial 47 | S & operator = (S &&) = default; 48 | 49 | ~S() = default; 50 | 51 | }; 52 | 53 | using U = V< S >; 54 | 55 | SA(std::is_trivial_v< S >); 56 | SA(!std::is_trivially_default_constructible_v< U >); 57 | SA(std::is_trivially_copyable_v< U >); 58 | 59 | SA(std::is_standard_layout_v< S >); 60 | SA(std::is_standard_layout_v< U >); 61 | 62 | SA(std::is_literal_type_v< S >); // constexpr defaulted default c-tor 63 | SA(std::is_literal_type_v< U >); 64 | 65 | SA(std::is_pod_v< S >); 66 | SA(!std::is_pod_v< U >); 67 | 68 | constexpr 69 | static 70 | bool 71 | run() noexcept 72 | { 73 | return true; 74 | } 75 | 76 | }; 77 | 78 | struct trivially_copyable 79 | { 80 | 81 | struct S 82 | { 83 | 84 | int i; 85 | S(int j) : i(j) { ; } 86 | 87 | S() { ; } 88 | 89 | S(S const &) = default; 90 | //S(S &) = default; // ?sould not be user-declared to be trivially copyable 91 | //S(S const &&) { ; } // ?sould not be user-declared/provided to be trivially copyable 92 | S(S &&) = default; 93 | 94 | S & operator = (S const &) = default; 95 | //S & operator = (S &) = default; // ?sould not be user-declared to be trivially copyable 96 | //S & operator = (S const &&) { return *this; } // ?sould not be user-declared/provided to be trivially copyable 97 | S & operator = (S &&) = default; 98 | 99 | ~S() = default; 100 | 101 | }; 102 | 103 | using U = V< S >; 104 | 105 | SA(!std::is_trivially_default_constructible_v< S >); 106 | SA(!std::is_trivially_default_constructible_v< U >); 107 | 108 | SA(std::is_trivially_copyable_v< S >); 109 | SA(std::is_trivially_copyable_v< U >); 110 | 111 | SA(std::is_standard_layout_v< S >); 112 | SA(std::is_standard_layout_v< U >); 113 | 114 | SA(!std::is_literal_type_v< S >); 115 | SA(!std::is_literal_type_v< U >); 116 | 117 | SA(!std::is_pod_v< S >); 118 | SA(!std::is_pod_v< U >); 119 | 120 | constexpr 121 | static 122 | bool 123 | run() noexcept 124 | { 125 | return true; 126 | } 127 | 128 | }; 129 | 130 | struct default_constructor 131 | { 132 | 133 | struct S 134 | { 135 | 136 | int i; 137 | S(int j) : i(j) { ; } 138 | 139 | S() { ; } 140 | 141 | S(S const &) = default; 142 | S(S &) = default; 143 | //S(S const &&) { ; } 144 | S(S &&) = default; 145 | 146 | S & operator = (S const &) = default; 147 | S & operator = (S &) = default; 148 | //S & operator = (S const &&) { return *this; } 149 | S & operator = (S &&) = default; 150 | 151 | ~S() = default; 152 | 153 | }; 154 | 155 | using U = V< S >; 156 | 157 | SA(std::is_default_constructible_v< S >); 158 | SA(std::is_default_constructible_v< U >); 159 | SA(!std::is_trivially_default_constructible_v< S >); 160 | SA(!std::is_trivially_default_constructible_v< U >); 161 | 162 | SA(std::is_destructible_v< S >); 163 | SA(std::is_destructible_v< U >); 164 | SA(std::is_trivially_destructible_v< S >); 165 | SA(std::is_trivially_destructible_v< U >); 166 | 167 | SA(std::is_copy_constructible_v< S >); 168 | SA(std::is_copy_constructible_v< U >); 169 | SA(is_vcopy_constructible_v< S >); 170 | SA(is_vcopy_constructible_v< U >); 171 | 172 | SA(std::is_move_constructible_v< S >); 173 | SA(std::is_move_constructible_v< U >); 174 | SA(is_cmove_constructible_v< S >); 175 | SA(is_cmove_constructible_v< U >); 176 | 177 | SA(std::is_trivially_copy_constructible_v< S >); 178 | SA(std::is_trivially_copy_constructible_v< U >); 179 | SA(!is_trivially_vcopy_constructible_v< S >); 180 | SA(is_trivially_vcopy_constructible_v< U >); 181 | 182 | SA(std::is_trivially_move_constructible_v< S >); 183 | SA(std::is_trivially_move_constructible_v< U >); 184 | SA(is_trivially_cmove_constructible_v< S >); 185 | SA(is_trivially_cmove_constructible_v< U >); 186 | 187 | SA(std::is_copy_assignable_v< S >); 188 | SA(std::is_copy_assignable_v< U >); 189 | SA(is_vcopy_assignable_v< S >); 190 | SA(is_vcopy_assignable_v< U >); 191 | 192 | SA(std::is_move_assignable_v< S >); 193 | SA(std::is_move_assignable_v< U >); 194 | SA(is_cmove_assignable_v< S >); 195 | SA(is_cmove_assignable_v< U >); 196 | 197 | SA(std::is_trivially_copy_assignable_v< S >); 198 | SA(std::is_trivially_copy_assignable_v< U >); 199 | SA(!is_trivially_vcopy_assignable_v< S >); 200 | SA(is_trivially_vcopy_assignable_v< U >); 201 | 202 | SA(std::is_trivially_move_assignable_v< S >); 203 | SA(std::is_trivially_move_assignable_v< U >); 204 | SA(is_trivially_cmove_assignable_v< S >); 205 | SA(is_trivially_cmove_assignable_v< U >); 206 | 207 | constexpr 208 | static 209 | bool 210 | run() noexcept 211 | { 212 | return true; 213 | } 214 | 215 | }; 216 | 217 | struct destructor 218 | { 219 | 220 | struct S 221 | { 222 | 223 | int i; 224 | S(int j) : i(j) { ; } 225 | 226 | S() = default; 227 | 228 | S(S const &) = default; 229 | S(S &) = default; 230 | //S(S const &&) { ; } 231 | S(S &&) = default; 232 | 233 | S & operator = (S const &) = default; 234 | S & operator = (S &) = default; 235 | //S & operator = (S const &&) { return *this; } 236 | S & operator = (S &&) = default; 237 | 238 | ~S() { ; } 239 | 240 | }; 241 | 242 | using U = V< S >; 243 | 244 | SA(std::is_default_constructible_v< S >); 245 | SA(std::is_default_constructible_v< U >); 246 | SA(!std::is_trivially_default_constructible_v< S >); // ! false 247 | SA(!std::is_trivially_default_constructible_v< U >); // ! 248 | 249 | SA(std::is_destructible_v< S >); 250 | SA(std::is_destructible_v< U >); 251 | SA(!std::is_trivially_destructible_v< S >); 252 | SA(!std::is_trivially_destructible_v< U >); 253 | 254 | SA(std::is_copy_constructible_v< S >); 255 | SA(std::is_copy_constructible_v< U >); 256 | SA(is_vcopy_constructible_v< S >); 257 | SA(is_vcopy_constructible_v< U >); 258 | 259 | SA(std::is_move_constructible_v< S >); 260 | SA(std::is_move_constructible_v< U >); 261 | SA(is_cmove_constructible_v< S >); 262 | SA(is_cmove_constructible_v< U >); 263 | 264 | SA(!std::is_trivially_copy_constructible_v< S >); // ? false 265 | SA(!std::is_trivially_copy_constructible_v< U >); // ? 266 | SA(!is_trivially_vcopy_constructible_v< S >); // ? 267 | SA(!is_trivially_vcopy_constructible_v< U >); // ? 268 | 269 | SA(!std::is_trivially_move_constructible_v< S >); // ? false 270 | SA(!std::is_trivially_move_constructible_v< U >); // ? 271 | SA(!is_trivially_cmove_constructible_v< S >); // ? 272 | SA(!is_trivially_cmove_constructible_v< U >); // ? 273 | 274 | SA(std::is_copy_assignable_v< S >); 275 | SA(std::is_copy_assignable_v< U >); 276 | SA(is_vcopy_assignable_v< S >); 277 | SA(is_vcopy_assignable_v< U >); 278 | 279 | SA(std::is_move_assignable_v< S >); 280 | SA(std::is_move_assignable_v< U >); 281 | SA(is_cmove_assignable_v< S >); 282 | SA(is_cmove_assignable_v< U >); 283 | 284 | SA(std::is_trivially_copy_assignable_v< S >); 285 | SA(std::is_trivially_copy_assignable_v< U >); 286 | SA(!is_trivially_vcopy_assignable_v< S >); 287 | SA(is_trivially_vcopy_assignable_v< U >); 288 | 289 | SA(std::is_trivially_move_assignable_v< S >); 290 | SA(std::is_trivially_move_assignable_v< U >); 291 | SA(is_trivially_cmove_assignable_v< S >); 292 | SA(is_trivially_cmove_assignable_v< U >); 293 | 294 | constexpr 295 | static 296 | bool 297 | run() noexcept 298 | { 299 | return true; 300 | } 301 | 302 | }; 303 | 304 | struct copy_constructor 305 | { 306 | 307 | struct S 308 | { 309 | 310 | int i; 311 | S(int j) : i(j) { ; } 312 | 313 | S() = default; 314 | 315 | S(S const &) { ; } 316 | S(S &) = default; 317 | //S(S const &&) { ; } 318 | S(S &&) = default; 319 | 320 | S & operator = (S const &) = default; 321 | S & operator = (S &) = default; 322 | //S & operator = (S const &&) { return *this; } 323 | S & operator = (S &&) = default; 324 | 325 | ~S() = default; 326 | 327 | }; 328 | 329 | using U = V< S >; 330 | 331 | SA(std::is_default_constructible_v< S >); 332 | SA(std::is_default_constructible_v< U >); 333 | SA(std::is_trivially_default_constructible_v< S >); 334 | SA(!std::is_trivially_default_constructible_v< U >); 335 | 336 | SA(std::is_destructible_v< S >); 337 | SA(std::is_destructible_v< U >); 338 | SA(std::is_trivially_destructible_v< S >); 339 | SA(std::is_trivially_destructible_v< U >); 340 | 341 | SA(std::is_copy_constructible_v< S >); 342 | SA(!std::is_copy_constructible_v< U >); 343 | SA(is_vcopy_constructible_v< S >); 344 | SA(!is_vcopy_constructible_v< U >); 345 | 346 | SA(std::is_move_constructible_v< S >); 347 | SA(std::is_move_constructible_v< U >); 348 | SA(is_cmove_constructible_v< S >); 349 | SA(!is_cmove_constructible_v< U >); 350 | 351 | SA(!std::is_trivially_copy_constructible_v< S >); 352 | SA(!std::is_trivially_copy_constructible_v< U >); 353 | SA(!is_trivially_vcopy_constructible_v< S >); 354 | SA(!is_trivially_vcopy_constructible_v< U >); 355 | 356 | SA(std::is_trivially_move_constructible_v< S >); 357 | SA(std::is_trivially_move_constructible_v< U >); 358 | SA(!is_trivially_cmove_constructible_v< S >); 359 | SA(!is_trivially_cmove_constructible_v< U >); 360 | 361 | SA(std::is_copy_assignable_v< S >); 362 | SA(std::is_copy_assignable_v< U >); 363 | SA(is_vcopy_assignable_v< S >); 364 | SA(is_vcopy_assignable_v< U >); 365 | 366 | SA(std::is_move_assignable_v< S >); 367 | SA(std::is_move_assignable_v< U >); 368 | SA(is_cmove_assignable_v< S >); 369 | SA(is_cmove_assignable_v< U >); 370 | 371 | SA(std::is_trivially_copy_assignable_v< S >); 372 | SA(std::is_trivially_copy_assignable_v< U >); 373 | SA(!is_trivially_vcopy_assignable_v< S >); // ? 374 | SA(is_trivially_vcopy_assignable_v< U >); 375 | 376 | SA(std::is_trivially_move_assignable_v< S >); 377 | SA(std::is_trivially_move_assignable_v< U >); 378 | SA(is_trivially_cmove_assignable_v< S >); 379 | SA(is_trivially_cmove_assignable_v< U >); 380 | 381 | constexpr 382 | static 383 | bool 384 | run() noexcept 385 | { 386 | return true; 387 | } 388 | 389 | }; 390 | 391 | struct vcopy_constructor 392 | { 393 | 394 | struct S 395 | { 396 | 397 | int i; 398 | S(int j) : i(j) { ; } 399 | 400 | S() = default; 401 | 402 | S(S const &) = default; 403 | S(S &) { ; } 404 | //S(S const &&) { ; } 405 | S(S &&) = default; 406 | 407 | S & operator = (S const &) = default; 408 | S & operator = (S &) = default; 409 | //S & operator = (S const &&) { return *this; } 410 | S & operator = (S &&) = default; 411 | 412 | ~S() = default; 413 | 414 | }; 415 | 416 | using U = V< S >; 417 | 418 | SA(std::is_default_constructible_v< S >); 419 | SA(std::is_default_constructible_v< U >); 420 | SA(std::is_trivially_default_constructible_v< S >); 421 | SA(!std::is_trivially_default_constructible_v< U >); 422 | 423 | SA(std::is_destructible_v< S >); 424 | SA(std::is_destructible_v< U >); 425 | SA(std::is_trivially_destructible_v< S >); 426 | SA(std::is_trivially_destructible_v< U >); 427 | 428 | SA(std::is_copy_constructible_v< S >); 429 | SA(std::is_copy_constructible_v< U >); 430 | SA(is_vcopy_constructible_v< S >); 431 | SA(is_vcopy_constructible_v< U >); 432 | 433 | SA(std::is_move_constructible_v< S >); 434 | SA(std::is_move_constructible_v< U >); 435 | SA(is_cmove_constructible_v< S >); 436 | SA(is_cmove_constructible_v< U >); 437 | 438 | SA(std::is_trivially_copy_constructible_v< S >); 439 | SA(std::is_trivially_copy_constructible_v< U >); 440 | SA(!is_trivially_vcopy_constructible_v< S >); 441 | SA(is_trivially_vcopy_constructible_v< U >); 442 | 443 | SA(std::is_trivially_move_constructible_v< S >); 444 | SA(std::is_trivially_move_constructible_v< U >); 445 | SA(is_trivially_cmove_constructible_v< S >); 446 | SA(is_trivially_cmove_constructible_v< U >); 447 | 448 | SA(std::is_copy_assignable_v< S >); 449 | SA(std::is_copy_assignable_v< U >); 450 | SA(is_vcopy_assignable_v< S >); 451 | SA(is_vcopy_assignable_v< U >); 452 | 453 | SA(std::is_move_assignable_v< S >); 454 | SA(std::is_move_assignable_v< U >); 455 | SA(is_cmove_assignable_v< S >); 456 | SA(is_cmove_assignable_v< U >); 457 | 458 | SA(std::is_trivially_copy_assignable_v< S >); 459 | SA(std::is_trivially_copy_assignable_v< U >); 460 | SA(!is_trivially_vcopy_assignable_v< S >); 461 | SA(is_trivially_vcopy_assignable_v< U >); 462 | 463 | SA(std::is_trivially_move_assignable_v< S >); 464 | SA(std::is_trivially_move_assignable_v< U >); 465 | SA(is_trivially_cmove_assignable_v< S >); 466 | SA(is_trivially_cmove_assignable_v< U >); 467 | 468 | constexpr 469 | static 470 | bool 471 | run() noexcept 472 | { 473 | return true; 474 | } 475 | 476 | }; 477 | 478 | struct move_constructor 479 | { 480 | 481 | struct S 482 | { 483 | 484 | int i; 485 | S(int j) : i(j) { ; } 486 | 487 | S() = default; 488 | 489 | S(S const &) = default; 490 | S(S &) = default; 491 | //S(S const &&) { ; } 492 | S(S &&) { ; } 493 | 494 | S & operator = (S const &) = default; 495 | S & operator = (S &) = default; 496 | //S & operator = (S const &&) { return *this; } 497 | S & operator = (S &&) = default; 498 | 499 | ~S() = default; 500 | 501 | }; 502 | 503 | using U = V< S >; 504 | 505 | SA(std::is_default_constructible_v< S >); 506 | SA(std::is_default_constructible_v< U >); 507 | SA(std::is_trivially_default_constructible_v< S >); 508 | SA(!std::is_trivially_default_constructible_v< U >); 509 | 510 | SA(std::is_destructible_v< S >); 511 | SA(std::is_destructible_v< U >); 512 | SA(std::is_trivially_destructible_v< S >); 513 | SA(std::is_trivially_destructible_v< U >); 514 | 515 | SA(std::is_copy_constructible_v< S >); 516 | SA(std::is_copy_constructible_v< U >); 517 | SA(is_vcopy_constructible_v< S >); 518 | SA(is_vcopy_constructible_v< U >); 519 | 520 | SA(std::is_move_constructible_v< S >); 521 | SA(std::is_move_constructible_v< U >); 522 | SA(is_cmove_constructible_v< S >); 523 | SA(is_cmove_constructible_v< U >); 524 | 525 | SA(std::is_trivially_copy_constructible_v< S >); 526 | SA(std::is_trivially_copy_constructible_v< U >); 527 | SA(!is_trivially_vcopy_constructible_v< S >); 528 | SA(is_trivially_vcopy_constructible_v< U >); 529 | 530 | SA(!std::is_trivially_move_constructible_v< S >); 531 | SA(!std::is_trivially_move_constructible_v< U >); 532 | SA(is_trivially_cmove_constructible_v< S >); 533 | SA(is_trivially_cmove_constructible_v< U >); 534 | 535 | SA(std::is_copy_assignable_v< S >); 536 | SA(std::is_copy_assignable_v< U >); 537 | SA(is_vcopy_assignable_v< S >); 538 | SA(is_vcopy_assignable_v< U >); 539 | 540 | SA(std::is_move_assignable_v< S >); 541 | SA(std::is_move_assignable_v< U >); 542 | SA(is_cmove_assignable_v< S >); 543 | SA(is_cmove_assignable_v< U >); 544 | 545 | SA(std::is_trivially_copy_assignable_v< S >); 546 | SA(std::is_trivially_copy_assignable_v< U >); 547 | SA(!is_trivially_vcopy_assignable_v< S >); 548 | SA(is_trivially_vcopy_assignable_v< U >); 549 | 550 | SA(std::is_trivially_move_assignable_v< S >); 551 | SA(std::is_trivially_move_assignable_v< U >); 552 | SA(is_trivially_cmove_assignable_v< S >); 553 | SA(is_trivially_cmove_assignable_v< U >); 554 | 555 | constexpr 556 | static 557 | bool 558 | run() noexcept 559 | { 560 | return true; 561 | } 562 | 563 | }; 564 | 565 | struct cmove_constructor 566 | { 567 | 568 | struct S 569 | { 570 | 571 | int i; 572 | S(int j) : i(j) { ; } 573 | 574 | S() = default; 575 | 576 | S(S const &) = default; 577 | S(S &) = default; 578 | /*!*/S(S const &&) { ; } 579 | S(S &&) = default; 580 | 581 | S & operator = (S const &) = default; 582 | S & operator = (S &) = default; 583 | //S & operator = (S const &&) { return *this; } 584 | S & operator = (S &&) = default; 585 | 586 | ~S() = default; 587 | 588 | }; 589 | 590 | using U = V< S >; 591 | 592 | SA(std::is_default_constructible_v< S >); 593 | SA(std::is_default_constructible_v< U >); 594 | SA(std::is_trivially_default_constructible_v< S >); 595 | SA(!std::is_trivially_default_constructible_v< U >); 596 | 597 | SA(std::is_destructible_v< S >); 598 | SA(std::is_destructible_v< U >); 599 | SA(std::is_trivially_destructible_v< S >); 600 | SA(std::is_trivially_destructible_v< U >); 601 | 602 | SA(std::is_copy_constructible_v< S >); 603 | SA(std::is_copy_constructible_v< U >); 604 | SA(is_vcopy_constructible_v< S >); 605 | SA(is_vcopy_constructible_v< U >); 606 | 607 | SA(std::is_move_constructible_v< S >); 608 | SA(std::is_move_constructible_v< U >); 609 | SA(is_cmove_constructible_v< S >); 610 | SA(is_cmove_constructible_v< U >); 611 | 612 | SA(std::is_trivially_copy_constructible_v< S >); 613 | SA(std::is_trivially_copy_constructible_v< U >); 614 | SA(!is_trivially_vcopy_constructible_v< S >); 615 | SA(is_trivially_vcopy_constructible_v< U >); 616 | 617 | SA(std::is_trivially_move_constructible_v< S >); 618 | SA(std::is_trivially_move_constructible_v< U >); 619 | SA(!is_trivially_cmove_constructible_v< S >); 620 | SA(is_trivially_cmove_constructible_v< U >); 621 | 622 | SA(std::is_copy_assignable_v< S >); 623 | SA(std::is_copy_assignable_v< U >); 624 | SA(is_vcopy_assignable_v< S >); 625 | SA(is_vcopy_assignable_v< U >); 626 | 627 | SA(std::is_move_assignable_v< S >); 628 | SA(std::is_move_assignable_v< U >); 629 | SA(is_cmove_assignable_v< S >); 630 | SA(is_cmove_assignable_v< U >); 631 | 632 | SA(std::is_trivially_copy_assignable_v< S >); 633 | SA(std::is_trivially_copy_assignable_v< U >); 634 | SA(!is_trivially_vcopy_assignable_v< S >); 635 | SA(is_trivially_vcopy_assignable_v< U >); 636 | 637 | SA(std::is_trivially_move_assignable_v< S >); 638 | SA(std::is_trivially_move_assignable_v< U >); 639 | SA(is_trivially_cmove_assignable_v< S >); 640 | SA(is_trivially_cmove_assignable_v< U >); 641 | 642 | constexpr 643 | static 644 | bool 645 | run() noexcept 646 | { 647 | return true; 648 | } 649 | 650 | }; 651 | 652 | struct copy_assignment 653 | { 654 | 655 | struct S 656 | { 657 | 658 | int i; 659 | S(int j) : i(j) { ; } 660 | 661 | S() = default; 662 | 663 | S(S const &) = default; 664 | S(S &) = default; 665 | //S(S const &&) { ; } 666 | S(S &&) = default; 667 | 668 | S & operator = (S const &) { ; } 669 | S & operator = (S &) = default; 670 | //S & operator = (S const &&) { return *this; } 671 | S & operator = (S &&) = default; 672 | 673 | ~S() = default; 674 | 675 | }; 676 | 677 | using U = V< S >; 678 | 679 | SA(std::is_default_constructible_v< S >); 680 | SA(std::is_default_constructible_v< U >); 681 | SA(std::is_trivially_default_constructible_v< S >); 682 | SA(!std::is_trivially_default_constructible_v< U >); 683 | 684 | SA(std::is_destructible_v< S >); 685 | SA(std::is_destructible_v< U >); 686 | SA(std::is_trivially_destructible_v< S >); 687 | SA(std::is_trivially_destructible_v< U >); 688 | 689 | SA(std::is_copy_constructible_v< S >); 690 | SA(std::is_copy_constructible_v< U >); 691 | SA(is_vcopy_constructible_v< S >); 692 | SA(is_vcopy_constructible_v< U >); 693 | 694 | SA(std::is_move_constructible_v< S >); 695 | SA(std::is_move_constructible_v< U >); 696 | SA(is_cmove_constructible_v< S >); 697 | SA(is_cmove_constructible_v< U >); 698 | 699 | SA(std::is_trivially_copy_constructible_v< S >); 700 | SA(std::is_trivially_copy_constructible_v< U >); 701 | SA(!is_trivially_vcopy_constructible_v< S >); 702 | SA(is_trivially_vcopy_constructible_v< U >); 703 | 704 | SA(std::is_trivially_move_constructible_v< S >); 705 | SA(std::is_trivially_move_constructible_v< U >); 706 | SA(is_trivially_cmove_constructible_v< S >); 707 | SA(is_trivially_cmove_constructible_v< U >); 708 | 709 | SA(std::is_copy_assignable_v< S >); 710 | SA(!std::is_copy_assignable_v< U >); 711 | SA(is_vcopy_assignable_v< S >); 712 | SA(!is_vcopy_assignable_v< U >); 713 | 714 | SA(std::is_move_assignable_v< S >); 715 | SA(std::is_move_assignable_v< U >); 716 | SA(is_cmove_assignable_v< S >); 717 | SA(!is_cmove_assignable_v< U >); 718 | 719 | SA(!std::is_trivially_copy_assignable_v< S >); 720 | SA(!std::is_trivially_copy_assignable_v< U >); 721 | SA(!is_trivially_vcopy_assignable_v< S >); 722 | SA(!is_trivially_vcopy_assignable_v< U >); 723 | 724 | SA(std::is_trivially_move_assignable_v< S >); 725 | SA(std::is_trivially_move_assignable_v< U >); 726 | SA(!is_trivially_cmove_assignable_v< S >); 727 | SA(!is_trivially_cmove_assignable_v< U >); 728 | 729 | constexpr 730 | static 731 | bool 732 | run() noexcept 733 | { 734 | return true; 735 | } 736 | 737 | }; 738 | 739 | struct vcopy_assignment 740 | { 741 | 742 | struct S 743 | { 744 | 745 | int i; 746 | S(int j) : i(j) { ; } 747 | 748 | S() = default; 749 | 750 | S(S const &) = default; 751 | S(S &) = default; 752 | //S(S const &&) { ; } 753 | S(S &&) = default; 754 | 755 | S & operator = (S const &) = default; 756 | S & operator = (S &) { ; } 757 | //S & operator = (S const &&) { return *this; } 758 | S & operator = (S &&) = default; 759 | 760 | ~S() = default; 761 | 762 | }; 763 | 764 | using U = V< S >; 765 | 766 | SA(std::is_default_constructible_v< S >); 767 | SA(std::is_default_constructible_v< U >); 768 | SA(std::is_trivially_default_constructible_v< S >); 769 | SA(!std::is_trivially_default_constructible_v< U >); 770 | 771 | SA(std::is_destructible_v< S >); 772 | SA(std::is_destructible_v< U >); 773 | SA(std::is_trivially_destructible_v< S >); 774 | SA(std::is_trivially_destructible_v< U >); 775 | 776 | SA(std::is_copy_constructible_v< S >); 777 | SA(std::is_copy_constructible_v< U >); 778 | SA(is_vcopy_constructible_v< S >); 779 | SA(is_vcopy_constructible_v< U >); 780 | 781 | SA(std::is_move_constructible_v< S >); 782 | SA(std::is_move_constructible_v< U >); 783 | SA(is_cmove_constructible_v< S >); 784 | SA(is_cmove_constructible_v< U >); 785 | 786 | SA(std::is_trivially_copy_constructible_v< S >); 787 | SA(std::is_trivially_copy_constructible_v< U >); 788 | SA(!is_trivially_vcopy_constructible_v< S >); 789 | SA(is_trivially_vcopy_constructible_v< U >); 790 | 791 | SA(std::is_trivially_move_constructible_v< S >); 792 | SA(std::is_trivially_move_constructible_v< U >); 793 | SA(is_trivially_cmove_constructible_v< S >); 794 | SA(is_trivially_cmove_constructible_v< U >); 795 | 796 | SA(std::is_copy_assignable_v< S >); 797 | SA(std::is_copy_assignable_v< U >); 798 | SA(is_vcopy_assignable_v< S >); 799 | SA(is_vcopy_assignable_v< U >); 800 | 801 | SA(std::is_move_assignable_v< S >); 802 | SA(std::is_move_assignable_v< U >); 803 | SA(is_cmove_assignable_v< S >); 804 | SA(is_cmove_assignable_v< U >); 805 | 806 | SA(std::is_trivially_copy_assignable_v< S >); 807 | SA(std::is_trivially_copy_assignable_v< U >); 808 | SA(!is_trivially_vcopy_assignable_v< S >); 809 | SA(is_trivially_vcopy_assignable_v< U >); 810 | 811 | SA(std::is_trivially_move_assignable_v< S >); 812 | SA(std::is_trivially_move_assignable_v< U >); 813 | SA(is_trivially_cmove_assignable_v< S >); 814 | SA(is_trivially_cmove_assignable_v< U >); 815 | 816 | constexpr 817 | static 818 | bool 819 | run() noexcept 820 | { 821 | return true; 822 | } 823 | 824 | }; 825 | 826 | struct move_assignment 827 | { 828 | 829 | struct S 830 | { 831 | 832 | int i; 833 | S(int j) : i(j) { ; } 834 | 835 | S() = default; 836 | 837 | S(S const &) = default; 838 | S(S &) = default; 839 | //S(S const &&) { ; } 840 | S(S &&) = default; 841 | 842 | S & operator = (S const &) = default; 843 | S & operator = (S &) = default; 844 | //S & operator = (S const &&) { return *this; } 845 | S & operator = (S &&) { return *this; } 846 | 847 | ~S() = default; 848 | 849 | }; 850 | 851 | using U = V< S >; 852 | 853 | SA(std::is_default_constructible_v< S >); 854 | SA(std::is_default_constructible_v< U >); 855 | SA(std::is_trivially_default_constructible_v< S >); 856 | SA(!std::is_trivially_default_constructible_v< U >); 857 | 858 | SA(std::is_destructible_v< S >); 859 | SA(std::is_destructible_v< U >); 860 | SA(std::is_trivially_destructible_v< S >); 861 | SA(std::is_trivially_destructible_v< U >); 862 | 863 | SA(std::is_copy_constructible_v< S >); 864 | SA(std::is_copy_constructible_v< U >); 865 | SA(is_vcopy_constructible_v< S >); 866 | SA(is_vcopy_constructible_v< U >); 867 | 868 | SA(std::is_move_constructible_v< S >); 869 | SA(std::is_move_constructible_v< U >); 870 | SA(is_cmove_constructible_v< S >); 871 | SA(is_cmove_constructible_v< U >); 872 | 873 | SA(std::is_trivially_copy_constructible_v< S >); 874 | SA(std::is_trivially_copy_constructible_v< U >); 875 | SA(!is_trivially_vcopy_constructible_v< S >); 876 | SA(is_trivially_vcopy_constructible_v< U >); 877 | 878 | SA(std::is_trivially_move_constructible_v< S >); 879 | SA(std::is_trivially_move_constructible_v< U >); 880 | SA(is_trivially_cmove_constructible_v< S >); 881 | SA(is_trivially_cmove_constructible_v< U >); 882 | 883 | SA(std::is_copy_assignable_v< S >); 884 | SA(std::is_copy_assignable_v< U >); 885 | SA(is_vcopy_assignable_v< S >); 886 | SA(is_vcopy_assignable_v< U >); 887 | 888 | SA(std::is_move_assignable_v< S >); 889 | SA(std::is_move_assignable_v< U >); 890 | SA(is_cmove_assignable_v< S >); 891 | SA(is_cmove_assignable_v< U >); 892 | 893 | SA(std::is_trivially_copy_assignable_v< S >); 894 | SA(std::is_trivially_copy_assignable_v< U >); 895 | SA(!is_trivially_vcopy_assignable_v< S >); 896 | SA(is_trivially_vcopy_assignable_v< U >); 897 | 898 | SA(!std::is_trivially_move_assignable_v< S >); 899 | SA(std::is_trivially_move_assignable_v< U >); 900 | SA(is_trivially_cmove_assignable_v< S >); 901 | SA(is_trivially_cmove_assignable_v< U >); 902 | 903 | constexpr 904 | static 905 | bool 906 | run() noexcept 907 | { 908 | return true; 909 | } 910 | 911 | }; 912 | 913 | struct cmove_assignment 914 | { 915 | 916 | struct S 917 | { 918 | 919 | int i; 920 | S(int j) : i(j) { ; } 921 | 922 | S() = default; 923 | 924 | S(S const &) = default; 925 | S(S &) = default; 926 | //S(S const &&) { ; } 927 | S(S &&) = default; 928 | 929 | S & operator = (S const &) = default; 930 | S & operator = (S &) = default; 931 | /*!*/S & operator = (S const &&) { return *this; } 932 | S & operator = (S &&) = default; 933 | 934 | ~S() = default; 935 | 936 | }; 937 | 938 | using U = V< S >; 939 | 940 | SA(std::is_default_constructible_v< S >); 941 | SA(std::is_default_constructible_v< U >); 942 | SA(std::is_trivially_default_constructible_v< S >); 943 | SA(!std::is_trivially_default_constructible_v< U >); 944 | 945 | SA(std::is_destructible_v< S >); 946 | SA(std::is_destructible_v< U >); 947 | SA(std::is_trivially_destructible_v< S >); 948 | SA(std::is_trivially_destructible_v< U >); 949 | 950 | SA(std::is_copy_constructible_v< S >); 951 | SA(std::is_copy_constructible_v< U >); 952 | SA(is_vcopy_constructible_v< S >); 953 | SA(is_vcopy_constructible_v< U >); 954 | 955 | SA(std::is_move_constructible_v< S >); 956 | SA(std::is_move_constructible_v< U >); 957 | SA(is_cmove_constructible_v< S >); 958 | SA(is_cmove_constructible_v< U >); 959 | 960 | SA(std::is_trivially_copy_constructible_v< S >); 961 | SA(std::is_trivially_copy_constructible_v< U >); 962 | SA(!is_trivially_vcopy_constructible_v< S >); 963 | SA(is_trivially_vcopy_constructible_v< U >); 964 | 965 | SA(std::is_trivially_move_constructible_v< S >); 966 | SA(std::is_trivially_move_constructible_v< U >); 967 | SA(is_trivially_cmove_constructible_v< S >); 968 | SA(is_trivially_cmove_constructible_v< U >); 969 | 970 | SA(std::is_copy_assignable_v< S >); 971 | SA(std::is_copy_assignable_v< U >); 972 | SA(is_vcopy_assignable_v< S >); 973 | SA(is_vcopy_assignable_v< U >); 974 | 975 | SA(std::is_move_assignable_v< S >); 976 | SA(std::is_move_assignable_v< U >); 977 | SA(is_cmove_assignable_v< S >); 978 | SA(is_cmove_assignable_v< U >); 979 | 980 | SA(std::is_trivially_copy_assignable_v< S >); 981 | SA(std::is_trivially_copy_assignable_v< U >); 982 | SA(!is_trivially_vcopy_assignable_v< S >); 983 | SA(is_trivially_vcopy_assignable_v< U >); 984 | 985 | SA(std::is_trivially_move_assignable_v< S >); 986 | SA(std::is_trivially_move_assignable_v< U >); 987 | SA(!is_trivially_cmove_assignable_v< S >); 988 | SA(is_trivially_cmove_assignable_v< U >); 989 | 990 | constexpr 991 | static 992 | bool 993 | run() noexcept 994 | { 995 | return true; 996 | } 997 | 998 | }; 999 | 1000 | template< typename C > 1001 | struct container 1002 | { 1003 | 1004 | using U = V< C >; 1005 | 1006 | SA(std::is_default_constructible_v< C >); 1007 | SA(std::is_default_constructible_v< U >); 1008 | SA(!std::is_trivially_default_constructible_v< C >); 1009 | SA(!std::is_trivially_default_constructible_v< U >); 1010 | 1011 | SA(std::is_destructible_v< C >); 1012 | SA(std::is_destructible_v< U >); 1013 | SA(!std::is_trivially_destructible_v< C >); 1014 | SA(!std::is_trivially_destructible_v< U >); 1015 | 1016 | SA(std::is_copy_constructible_v< C >); 1017 | SA(!std::is_copy_constructible_v< U >); 1018 | SA(is_vcopy_constructible_v< C >); 1019 | SA(!is_vcopy_constructible_v< U >); 1020 | 1021 | SA(std::is_move_constructible_v< C >); 1022 | SA(std::is_move_constructible_v< U >); // ? 1023 | SA(is_cmove_constructible_v< C >); 1024 | SA(!is_cmove_constructible_v< U >); 1025 | 1026 | SA(!std::is_trivially_copy_constructible_v< C >); 1027 | SA(!std::is_trivially_copy_constructible_v< U >); 1028 | SA(!is_trivially_vcopy_constructible_v< C >); 1029 | SA(!is_trivially_vcopy_constructible_v< U >); 1030 | 1031 | SA(!std::is_trivially_move_constructible_v< C >); 1032 | SA(!std::is_trivially_move_constructible_v< U >); 1033 | SA(!is_trivially_cmove_constructible_v< C >); 1034 | SA(!is_trivially_cmove_constructible_v< U >); 1035 | 1036 | SA(std::is_copy_assignable_v< C >); 1037 | SA(!std::is_copy_assignable_v< U >); 1038 | SA(is_vcopy_assignable_v< C >); 1039 | SA(!is_vcopy_assignable_v< U >); 1040 | 1041 | SA(std::is_move_assignable_v< C >); 1042 | SA(!std::is_move_assignable_v< U >); 1043 | SA(is_cmove_assignable_v< C >); 1044 | SA(!is_cmove_assignable_v< U >); 1045 | 1046 | SA(!std::is_trivially_copy_assignable_v< C >); 1047 | SA(!std::is_trivially_copy_assignable_v< U >); 1048 | SA(!is_trivially_vcopy_assignable_v< C >); 1049 | SA(!is_trivially_vcopy_assignable_v< U >); 1050 | 1051 | SA(!std::is_trivially_move_assignable_v< C >); 1052 | SA(!std::is_trivially_move_assignable_v< U >); 1053 | SA(!is_trivially_cmove_assignable_v< C >); 1054 | SA(!is_trivially_cmove_assignable_v< U >); 1055 | 1056 | constexpr 1057 | static 1058 | bool 1059 | run() noexcept 1060 | { 1061 | return true; 1062 | } 1063 | 1064 | }; 1065 | 1066 | public : 1067 | 1068 | constexpr 1069 | static 1070 | bool 1071 | run() noexcept // just for implicit instantiation 1072 | { 1073 | { // all std::containers are identical 1074 | using S = common_type<>; 1075 | SA(container< std::string >::run()); 1076 | SA(container< std::vector< S > >::run()); 1077 | SA(container< std::deque< S > >::run()); 1078 | SA(container< std::list< S > >::run()); 1079 | } 1080 | SA(trivial ::run()); 1081 | SA(trivially_copyable ::run()); 1082 | SA(default_constructor ::run()); 1083 | SA(destructor ::run()); 1084 | SA(copy_constructor ::run()); 1085 | SA(vcopy_constructor ::run()); 1086 | SA(move_constructor ::run()); 1087 | SA(cmove_constructor ::run()); 1088 | SA(copy_assignment ::run()); 1089 | SA(vcopy_assignment ::run()); 1090 | SA(move_assignment ::run()); 1091 | SA(cmove_assignment ::run()); 1092 | return true; 1093 | } 1094 | 1095 | }; 1096 | 1097 | template< template< typename ... > class wrapper, 1098 | template< typename ... > class versatile > 1099 | class check_triviality 1100 | { 1101 | 1102 | template< typename ...types > 1103 | using V = versatile< typename wrapper< types >::type... >; 1104 | 1105 | CONSTEXPRF 1106 | static 1107 | bool 1108 | trivially_default_constructible() noexcept 1109 | { 1110 | struct S 1111 | { 1112 | CONSTEXPRF S() = default; 1113 | CONSTEXPRF S(S const &) { ; } 1114 | CONSTEXPRF S(S &) { ; } 1115 | CONSTEXPRF S(S const &&) { ; } 1116 | CONSTEXPRF S(S &&) { ; } 1117 | CONSTEXPRF S & operator = (S const &) { return *this; } 1118 | CONSTEXPRF S & operator = (S &) { return *this; } 1119 | CONSTEXPRF S & operator = (S const &&) { return *this; } 1120 | CONSTEXPRF S & operator = (S &&) { return *this; } 1121 | //~S() DESTRUCTOR 1122 | }; 1123 | SA(std::is_trivially_default_constructible_v< S >); 1124 | struct N {}; 1125 | SA(std::is_trivially_default_constructible_v< N >); 1126 | { 1127 | using U = V< S, N >; 1128 | SA(!std::is_trivially_default_constructible_v< U >); 1129 | { 1130 | CONSTEXPR U v{}; 1131 | ASSERT ( is_active< S >(v)); 1132 | ASSERT (!is_active< N >(v)); // check is_active itself 1133 | } 1134 | { 1135 | U v{}; 1136 | CHECK ( is_active< S >(v)); 1137 | CHECK (!is_active< N >(v)); 1138 | } 1139 | } 1140 | { 1141 | using U = V< N, S >; 1142 | SA(!std::is_trivially_default_constructible_v< U >); 1143 | { 1144 | CONSTEXPR U v{}; 1145 | ASSERT ( is_active< N >(v)); 1146 | ASSERT (!is_active< S >(v)); 1147 | } 1148 | { 1149 | U v{}; 1150 | CHECK ( is_active< N >(v)); 1151 | CHECK (!is_active< S >(v)); 1152 | } 1153 | } 1154 | return true; 1155 | } 1156 | 1157 | CONSTEXPRF 1158 | static 1159 | bool 1160 | trivially_copy_move_constructible() noexcept 1161 | { 1162 | struct S 1163 | { 1164 | CONSTEXPRF S() { ; } 1165 | CONSTEXPRF S(S const &) = default; 1166 | CONSTEXPRF S(S &) = default; 1167 | //CONSTEXPRF S(S const &&) { ; } 1168 | CONSTEXPRF S(S &&) = default; 1169 | CONSTEXPRF S & operator = (S const &) { return *this; } 1170 | CONSTEXPRF S & operator = (S &) { return *this; } 1171 | //CONSTEXPRF S & operator = (S const &&) { return *this; } 1172 | CONSTEXPRF S & operator = (S &&) { return *this; } 1173 | ~S() = default; 1174 | }; 1175 | SA(std::is_trivially_copy_constructible_v< S >); 1176 | SA(!is_trivially_vcopy_constructible_v< S > ); // ? 1177 | SA(std::is_trivially_move_constructible_v< S >); 1178 | SA(is_trivially_cmove_constructible_v< S > ); 1179 | SA(std::is_copy_constructible_v< S > ); 1180 | SA(is_vcopy_constructible_v< S > ); 1181 | SA(std::is_move_constructible_v< S > ); 1182 | SA(is_cmove_constructible_v< S > ); 1183 | struct N {}; 1184 | SA(std::is_trivial_v< N >); 1185 | { 1186 | using U = V< S, N >; 1187 | SA(std::is_trivially_copy_constructible_v< U >); 1188 | SA(is_trivially_vcopy_constructible_v< U >); 1189 | SA(std::is_trivially_move_constructible_v< U >); 1190 | SA(is_trivially_cmove_constructible_v< U >); 1191 | SA(std::is_copy_constructible_v< U >); 1192 | SA(is_vcopy_constructible_v< U >); 1193 | SA(std::is_move_constructible_v< U >); 1194 | SA(is_cmove_constructible_v< U >); 1195 | { 1196 | CONSTEXPR U v{N{}}; 1197 | ASSERT (is_active< N >(v)); 1198 | CONSTEXPR U w{v}; 1199 | ASSERT (is_active< N >(w)); 1200 | } 1201 | { 1202 | CONSTEXPR U v{S{}}; 1203 | ASSERT (is_active< S >(v)); 1204 | CONSTEXPR U w{v}; 1205 | ASSERT (is_active< S >(w)); 1206 | } 1207 | { 1208 | U v{N{}}; 1209 | CHECK (is_active< N >(v)); 1210 | U const w{v}; 1211 | CHECK (is_active< N >(w)); 1212 | } 1213 | { 1214 | U v{S{}}; 1215 | CHECK (is_active< S >(v)); 1216 | U const w{v}; 1217 | CHECK (is_active< S >(w)); 1218 | } 1219 | { 1220 | CONSTEXPR U v{N{}}; 1221 | ASSERT (is_active< N >(v)); 1222 | CONSTEXPR U w{std::move(v)}; 1223 | ASSERT (is_active< N >(w)); 1224 | } 1225 | { 1226 | CONSTEXPR U v{S{}}; 1227 | ASSERT (is_active< S >(v)); 1228 | CONSTEXPR U w{std::move(v)}; 1229 | ASSERT (is_active< S >(w)); 1230 | } 1231 | { 1232 | U v{N{}}; 1233 | CHECK (is_active< N >(v)); 1234 | U const w{std::move(v)}; 1235 | CHECK (is_active< N >(w)); 1236 | } 1237 | { 1238 | U v{S{}}; 1239 | CHECK (is_active< S >(v)); 1240 | U const w{std::move(v)}; 1241 | CHECK (is_active< S >(w)); 1242 | } 1243 | } 1244 | { 1245 | using U = V< N, S >; 1246 | SA(std::is_trivially_copy_constructible_v< U >); 1247 | SA(is_trivially_vcopy_constructible_v< U >); 1248 | SA(std::is_trivially_move_constructible_v< U >); 1249 | SA(is_trivially_cmove_constructible_v< U >); 1250 | SA(std::is_copy_constructible_v< U >); 1251 | SA(is_vcopy_constructible_v< U >); 1252 | SA(std::is_move_constructible_v< U >); 1253 | SA(is_cmove_constructible_v< U >); 1254 | { 1255 | CONSTEXPR U v{N{}}; 1256 | ASSERT (is_active< N >(v)); 1257 | CONSTEXPR U w{v}; 1258 | ASSERT (is_active< N >(w)); 1259 | } 1260 | { 1261 | CONSTEXPR U v{S{}}; 1262 | ASSERT (is_active< S >(v)); 1263 | CONSTEXPR U w{v}; 1264 | ASSERT (is_active< S >(w)); 1265 | } 1266 | { 1267 | U v{N{}}; 1268 | CHECK (is_active< N >(v)); 1269 | U const w{v}; 1270 | CHECK (is_active< N >(w)); 1271 | } 1272 | { 1273 | U v{S{}}; 1274 | CHECK (is_active< S >(v)); 1275 | U const w{v}; 1276 | CHECK (is_active< S >(w)); 1277 | } 1278 | { 1279 | CONSTEXPR U v{N{}}; 1280 | ASSERT (is_active< N >(v)); 1281 | CONSTEXPR U w{std::move(v)}; 1282 | ASSERT (is_active< N >(w)); 1283 | } 1284 | { 1285 | CONSTEXPR U v{S{}}; 1286 | ASSERT (is_active< S >(v)); 1287 | CONSTEXPR U w{std::move(v)}; 1288 | ASSERT (is_active< S >(w)); 1289 | } 1290 | { 1291 | U v{N{}}; 1292 | CHECK (is_active< N >(v)); 1293 | U const w{std::move(v)}; 1294 | CHECK (is_active< N >(w)); 1295 | } 1296 | { 1297 | U v{S{}}; 1298 | CHECK (is_active< S >(v)); 1299 | U const w{std::move(v)}; 1300 | CHECK (is_active< S >(w)); 1301 | } 1302 | } 1303 | return true; 1304 | } 1305 | 1306 | CONSTEXPRF 1307 | static 1308 | bool 1309 | trivially_copy_move_assignable() noexcept 1310 | { 1311 | struct S 1312 | { 1313 | CONSTEXPRF S() { ; } 1314 | CONSTEXPRF S(S const &) = default; 1315 | CONSTEXPRF S(S &) = default; 1316 | //CONSTEXPRF S(S const &&) { ; } 1317 | CONSTEXPRF S(S &&) = default; 1318 | CONSTEXPRF S & operator = (S const &) = default; 1319 | CONSTEXPRF S & operator = (S &) = default; 1320 | //CONSTEXPRF S & operator = (S const &&) { return *this; } 1321 | CONSTEXPRF S & operator = (S &&) = default; 1322 | //~S() DESTRUCTOR // clang bug: if destructor is user-declared and defaulted, then defaulted assignment operators become non-trivial and marked as non-constexpr 1323 | }; 1324 | SA(std::is_trivially_copy_assignable_v< S >); 1325 | SA(!is_trivially_vcopy_assignable_v< S > ); // ? 1326 | SA(std::is_trivially_move_assignable_v< S >); 1327 | SA(is_trivially_cmove_assignable_v< S > ); 1328 | SA(std::is_copy_assignable_v< S > ); 1329 | SA(is_vcopy_assignable_v< S > ); 1330 | SA(std::is_move_assignable_v< S > ); 1331 | SA(is_cmove_assignable_v< S > ); 1332 | struct N {}; 1333 | SA(std::is_trivial_v< N >); 1334 | { 1335 | using U = V< S, N >; 1336 | SA(std::is_trivially_copy_assignable_v< U >); 1337 | SA(is_trivially_vcopy_assignable_v< U >); 1338 | SA(std::is_trivially_move_assignable_v< U >); 1339 | SA(is_trivially_cmove_assignable_v< U >); 1340 | SA(std::is_copy_assignable_v< U >); 1341 | SA(is_vcopy_assignable_v< U >); 1342 | SA(std::is_move_assignable_v< U >); 1343 | SA(is_cmove_assignable_v< U >); 1344 | { 1345 | CONSTEXPR U v{N{}}; 1346 | ASSERT (is_active< N >(v)); 1347 | U w{}; 1348 | CHECK (is_active< S >(w)); 1349 | w = v; 1350 | CHECK (is_active< N >(w)); 1351 | } 1352 | { 1353 | CONSTEXPR U v{S{}}; 1354 | ASSERT (is_active< S >(v)); 1355 | U w{}; 1356 | CHECK (is_active< S >(w)); 1357 | w = v; 1358 | CHECK (is_active< S >(w)); 1359 | } 1360 | { 1361 | U v{N{}}; 1362 | CHECK (is_active< N >(v)); 1363 | U w{}; 1364 | CHECK (is_active< S >(w)); 1365 | w = v; 1366 | CHECK (is_active< N >(w)); 1367 | } 1368 | { 1369 | U v{S{}}; 1370 | CHECK (is_active< S >(v)); 1371 | U w{}; 1372 | CHECK (is_active< S >(w)); 1373 | w = v; 1374 | CHECK (is_active< S >(w)); 1375 | } 1376 | { 1377 | CONSTEXPR U v{N{}}; 1378 | ASSERT (is_active< N >(v)); 1379 | U w{}; 1380 | CHECK (is_active< S >(w)); 1381 | w = std::move(v); 1382 | CHECK (is_active< N >(w)); 1383 | } 1384 | { 1385 | CONSTEXPR U v{S{}}; 1386 | ASSERT (is_active< S >(v)); 1387 | U w{}; 1388 | CHECK (is_active< S >(w)); 1389 | w = std::move(v); 1390 | CHECK (is_active< S >(w)); 1391 | } 1392 | { 1393 | U v{N{}}; 1394 | CHECK (is_active< N >(v)); 1395 | U w{}; 1396 | CHECK (is_active< S >(w)); 1397 | w = std::move(v); 1398 | CHECK (is_active< N >(w)); 1399 | } 1400 | { 1401 | U v{S{}}; 1402 | CHECK (is_active< S >(v)); 1403 | U w{}; 1404 | CHECK (is_active< S >(w)); 1405 | w = std::move(v); 1406 | CHECK (is_active< S >(w)); 1407 | } 1408 | } 1409 | { 1410 | using U = V< N, S >; 1411 | SA(std::is_trivially_copy_assignable_v< U >); 1412 | SA(is_trivially_vcopy_assignable_v< U >); 1413 | SA(std::is_trivially_move_assignable_v< U >); 1414 | SA(is_trivially_cmove_assignable_v< U >); 1415 | SA(std::is_copy_assignable_v< U >); 1416 | SA(is_vcopy_assignable_v< U >); 1417 | SA(std::is_move_assignable_v< U >); 1418 | SA(is_cmove_assignable_v< U >); 1419 | { 1420 | CONSTEXPR U v{N{}}; 1421 | ASSERT (is_active< N >(v)); 1422 | U w{}; 1423 | CHECK (is_active< N >(w)); 1424 | w = v; 1425 | CHECK (is_active< N >(w)); 1426 | } 1427 | { 1428 | CONSTEXPR U v{S{}}; 1429 | ASSERT (is_active< S >(v)); 1430 | U w{}; 1431 | CHECK (is_active< N >(w)); 1432 | w = v; 1433 | CHECK (is_active< S >(w)); 1434 | } 1435 | { 1436 | U v{N{}}; 1437 | CHECK (is_active< N >(v)); 1438 | U w{}; 1439 | CHECK (is_active< N >(w)); 1440 | w = v; 1441 | CHECK (is_active< N >(w)); 1442 | } 1443 | { 1444 | U v{S{}}; 1445 | CHECK (is_active< S >(v)); 1446 | U w{}; 1447 | CHECK (is_active< N >(w)); 1448 | w = v; 1449 | CHECK (is_active< S >(w)); 1450 | } 1451 | { 1452 | CONSTEXPR U v{N{}}; 1453 | ASSERT (is_active< N >(v)); 1454 | U w{}; 1455 | CHECK (is_active< N >(w)); 1456 | w = std::move(v); 1457 | CHECK (is_active< N >(w)); 1458 | } 1459 | { 1460 | CONSTEXPR U v{S{}}; 1461 | ASSERT (is_active< S >(v)); 1462 | U w{}; 1463 | CHECK (is_active< N >(w)); 1464 | w = std::move(v); 1465 | CHECK (is_active< S >(w)); 1466 | } 1467 | { 1468 | U v{N{}}; 1469 | CHECK (is_active< N >(v)); 1470 | U w{}; 1471 | CHECK (is_active< N >(w)); 1472 | w = std::move(v); 1473 | CHECK (is_active< N >(w)); 1474 | } 1475 | { 1476 | U v{S{}}; 1477 | CHECK (is_active< S >(v)); 1478 | U w{}; 1479 | CHECK (is_active< N >(w)); 1480 | w = std::move(v); 1481 | CHECK (is_active< S >(w)); 1482 | } 1483 | } 1484 | return true; 1485 | } 1486 | 1487 | enum class state 1488 | { 1489 | never_used = 0, 1490 | default_constructed, 1491 | copy_constructed, 1492 | vcopy_constructed, 1493 | move_constructed, 1494 | cmove_constructed, 1495 | copy_assigned, 1496 | vcopy_assigned, 1497 | move_assigned, 1498 | cmove_assigned, 1499 | moved_from, 1500 | }; 1501 | 1502 | SA(state::never_used == state{}); 1503 | 1504 | CONSTEXPRF 1505 | static 1506 | bool 1507 | convertible() noexcept 1508 | { 1509 | struct S 1510 | { 1511 | state state_ = state::never_used; 1512 | CONSTEXPRF S() : state_{state::default_constructed} { ; } 1513 | CONSTEXPRF S(S const &) : state_{state::copy_constructed} { ; } 1514 | CONSTEXPRF S(S &) : state_{state::vcopy_constructed} { ; } 1515 | //CONSTEXPRF S(S const &&) { state_ = state::cmove_constructed; } 1516 | CONSTEXPRF S(S && s) : state_{state::move_constructed} { s.state_ = state::moved_from; } 1517 | CONSTEXPRF S & operator = (S const &) { state_ = state::copy_assigned; return *this; } 1518 | CONSTEXPRF S & operator = (S &) { state_ = state::vcopy_assigned; return *this; } 1519 | //CONSTEXPRF S & operator = (S const &&) { state_ = state::cmove_assigned; return *this; } 1520 | CONSTEXPRF S & operator = (S && s) { state_ = state::move_assigned; s.state_ = state::moved_from; return *this; } 1521 | ~S() DESTRUCTOR 1522 | }; 1523 | SA(!std::is_trivially_copy_constructible_v< S >); 1524 | SA(!is_trivially_vcopy_constructible_v< S > ); 1525 | SA(!std::is_trivially_move_constructible_v< S >); 1526 | SA(!is_trivially_cmove_constructible_v< S > ); 1527 | SA(std::is_copy_constructible_v< S > ); 1528 | SA(is_vcopy_constructible_v< S > ); 1529 | SA(std::is_move_constructible_v< S > ); 1530 | SA(is_cmove_constructible_v< S > ); 1531 | SA(!std::is_trivially_copy_assignable_v< S > ); 1532 | SA(!is_trivially_vcopy_assignable_v< S > ); 1533 | SA(!std::is_trivially_move_assignable_v< S > ); 1534 | SA(!is_trivially_cmove_assignable_v< S > ); 1535 | SA(std::is_copy_assignable_v< S > ); 1536 | SA(is_vcopy_assignable_v< S > ); 1537 | SA(std::is_move_assignable_v< S > ); 1538 | SA(is_cmove_assignable_v< S > ); 1539 | { 1540 | using U = V< S >; 1541 | SA(!std::is_trivially_copy_constructible_v< U >); 1542 | SA(!is_trivially_vcopy_constructible_v< U >); 1543 | SA(!std::is_trivially_move_constructible_v< U >); 1544 | SA(!is_trivially_cmove_constructible_v< U >); 1545 | SA(!std::is_copy_constructible_v< U >); 1546 | SA(!is_vcopy_constructible_v< U >); 1547 | SA(std::is_move_constructible_v< U >); // ? 1548 | SA(!is_cmove_constructible_v< U >); 1549 | SA(!std::is_trivially_copy_assignable_v< U >); 1550 | SA(!is_trivially_vcopy_assignable_v< U >); 1551 | SA(!std::is_trivially_move_assignable_v< U >); 1552 | SA(!is_trivially_cmove_assignable_v< U >); 1553 | SA(!std::is_copy_assignable_v< U >); 1554 | SA(!is_vcopy_assignable_v< U >); 1555 | SA(!std::is_move_assignable_v< U >); 1556 | SA(!is_cmove_assignable_v< U >); 1557 | SA(!is_convertible_v< U, S >); 1558 | SA(!is_convertible_v< U const, S >); 1559 | SA(!is_convertible_v< U &, S >); 1560 | SA(!is_convertible_v< U const &, S >); 1561 | SA(is_explicitly_convertible_v< U, S >); 1562 | SA(is_explicitly_convertible_v< U const, S >); 1563 | SA(is_explicitly_convertible_v< U &, S >); 1564 | SA(is_explicitly_convertible_v< U const &, S >); 1565 | SA(is_convertible_v< S, U >); 1566 | SA(is_convertible_v< S const, U >); 1567 | SA(is_convertible_v< S &, U >); 1568 | SA(is_convertible_v< S const &, U >); 1569 | { 1570 | struct T {}; 1571 | SA(!is_explicitly_convertible_v< U, T >); // SFINAE-disabled conversions 1572 | SA(!is_explicitly_convertible_v< U const, T >); // SFINAE-disabled conversions 1573 | SA(!is_explicitly_convertible_v< U &, T >); // SFINAE-disabled conversions 1574 | SA(!is_explicitly_convertible_v< U const &, T >); // SFINAE-disabled conversions 1575 | } 1576 | { 1577 | CONSTEXPR U v{}; 1578 | ASSERT (is_active< S >(v)); 1579 | ASSERT (static_cast< S const & >(v).state_ == state::default_constructed); 1580 | CONSTEXPR S s{v}; 1581 | ASSERT (static_cast< S const & >(v).state_ == state::default_constructed); 1582 | ASSERT (s.state_ == state::copy_constructed); 1583 | } 1584 | { 1585 | U v{}; 1586 | CHECK (is_active< S >(v)); 1587 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 1588 | S const s{v}; 1589 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 1590 | CHECK (s.state_ == state::vcopy_constructed); 1591 | } 1592 | { 1593 | CONSTEXPR U v{}; 1594 | ASSERT (is_active< S >(v)); 1595 | ASSERT (static_cast< S const & >(v).state_ == state::default_constructed); 1596 | CONSTEXPR S l{std::move(v)}; 1597 | ASSERT (static_cast< S const & >(v).state_ == state::default_constructed); 1598 | ASSERT (l.state_ == state::copy_constructed); // only lvalue-reference conversion operator currently is available 1599 | CONSTEXPR S r = std::move(static_cast< S const & >(v)); 1600 | ASSERT (static_cast< S const & >(v).state_ == state::default_constructed); 1601 | ASSERT (r.state_ == state::copy_constructed); // `const &` operator win 1602 | } 1603 | { 1604 | U v{}; 1605 | CHECK (is_active< S >(v)); 1606 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 1607 | S const l{std::move(v)}; 1608 | CHECK (static_cast< S & >(v).state_ == state::default_constructed); 1609 | CHECK (l.state_ == state::vcopy_constructed); // only lvalue-reference to const conversion operator currently is available 1610 | S const r = std::move(static_cast< S & >(v)); 1611 | CHECK (static_cast< S & >(v).state_ == state::moved_from); 1612 | CHECK (r.state_ == state::move_constructed); 1613 | } 1614 | } 1615 | return true; 1616 | } 1617 | 1618 | CONSTEXPRF 1619 | static 1620 | bool 1621 | constructible() noexcept 1622 | { 1623 | struct S 1624 | { 1625 | state state_ = state::never_used; 1626 | CONSTEXPRF S() : state_{state::default_constructed} { ; } 1627 | CONSTEXPRF S(S const &) : state_{state::copy_constructed} { ; } 1628 | CONSTEXPRF S(S &) : state_{state::vcopy_constructed} { ; } 1629 | //CONSTEXPRF S(S const &&) { state_ = state::cmove_constructed; } 1630 | CONSTEXPRF S(S && s) : state_{state::move_constructed} { s.state_ = state::moved_from; } 1631 | CONSTEXPRF S & operator = (S const &) { state_ = state::copy_assigned; return *this; } 1632 | CONSTEXPRF S & operator = (S &) { state_ = state::vcopy_assigned; return *this; } 1633 | //CONSTEXPRF S & operator = (S const &&) { state_ = state::cmove_assigned; return *this; } 1634 | CONSTEXPRF S & operator = (S && s) { state_ = state::move_assigned; s.state_ = state::moved_from; return *this; } 1635 | ~S() DESTRUCTOR 1636 | }; 1637 | SA(!std::is_trivially_copy_constructible_v< S >); 1638 | SA(!is_trivially_vcopy_constructible_v< S > ); // ? 1639 | SA(!std::is_trivially_move_constructible_v< S >); 1640 | SA(!is_trivially_cmove_constructible_v< S > ); 1641 | SA(std::is_copy_constructible_v< S > ); 1642 | SA(is_vcopy_constructible_v< S > ); 1643 | SA(std::is_move_constructible_v< S > ); 1644 | SA(is_cmove_constructible_v< S > ); 1645 | SA(!std::is_trivially_copy_assignable_v< S > ); 1646 | SA(!is_trivially_vcopy_assignable_v< S > ); // ? 1647 | SA(!std::is_trivially_move_assignable_v< S > ); 1648 | SA(!is_trivially_cmove_assignable_v< S > ); 1649 | SA(std::is_copy_assignable_v< S > ); 1650 | SA(is_vcopy_assignable_v< S > ); 1651 | SA(std::is_move_assignable_v< S > ); 1652 | SA(is_cmove_assignable_v< S > ); 1653 | struct N {}; 1654 | SA(std::is_trivial_v< N >); 1655 | { 1656 | using U = V< S, N >; 1657 | SA(!std::is_trivially_copy_constructible_v< U >); 1658 | SA(!is_trivially_vcopy_constructible_v< U >); // ? 1659 | SA(!std::is_trivially_move_constructible_v< U >); 1660 | SA(!is_trivially_cmove_constructible_v< U >); 1661 | SA(!std::is_copy_constructible_v< U >); 1662 | SA(!is_vcopy_constructible_v< U >); 1663 | SA(std::is_move_constructible_v< U >); // ? 1664 | SA(!is_cmove_constructible_v< U >); 1665 | SA(!std::is_trivially_copy_assignable_v< U >); 1666 | SA(!is_trivially_vcopy_assignable_v< U >); // ? 1667 | SA(!std::is_trivially_move_assignable_v< U >); 1668 | SA(!is_trivially_cmove_assignable_v< U >); 1669 | SA(!std::is_copy_assignable_v< U >); 1670 | SA(!is_vcopy_assignable_v< U >); 1671 | SA(!std::is_move_assignable_v< U >); 1672 | SA(!is_cmove_assignable_v< U >); 1673 | { 1674 | CONSTEXPR S s{}; 1675 | ASSERT (s.state_ == state::default_constructed); 1676 | CONSTEXPR U v{s}; 1677 | ASSERT (is_active< S >(v)); 1678 | ASSERT (static_cast< S const & >(v).state_ == state::copy_constructed); 1679 | ASSERT (s.state_ == state::default_constructed); 1680 | } 1681 | { 1682 | S s; 1683 | CHECK (s.state_ == state::default_constructed); 1684 | U v{s}; 1685 | CHECK (is_active< S >(v)); 1686 | CHECK (static_cast< S & >(v).state_ == state::vcopy_constructed); 1687 | CHECK (s.state_ == state::default_constructed); 1688 | } 1689 | { 1690 | CONSTEXPR S s{}; 1691 | ASSERT (s.state_ == state::default_constructed); 1692 | CONSTEXPR U v{std::move(s)}; 1693 | ASSERT (is_active< S >(v)); 1694 | ASSERT (static_cast< S const & >(v).state_ == state::copy_constructed); // `const &` operator win 1695 | ASSERT (s.state_ == state::default_constructed); 1696 | } 1697 | { 1698 | S s; 1699 | CHECK (s.state_ == state::default_constructed); 1700 | U v{std::move(s)}; 1701 | CHECK (is_active< S >(v)); 1702 | CHECK (static_cast< S & >(v).state_ == state::move_constructed); 1703 | CHECK (s.state_ == state::moved_from); 1704 | } 1705 | } 1706 | { 1707 | using U = V< N, S >; 1708 | SA(!std::is_trivially_copy_constructible_v< U >); 1709 | SA(!is_trivially_vcopy_constructible_v< U >); // ? 1710 | SA(!std::is_trivially_move_constructible_v< U >); 1711 | SA(!is_trivially_cmove_constructible_v< U >); 1712 | SA(!std::is_copy_constructible_v< U >); 1713 | SA(!is_vcopy_constructible_v< U >); 1714 | SA(std::is_move_constructible_v< U >); // ? 1715 | SA(!is_cmove_constructible_v< U >); 1716 | SA(!std::is_trivially_copy_assignable_v< U >); 1717 | SA(!is_trivially_vcopy_assignable_v< U >); // ? 1718 | SA(!std::is_trivially_move_assignable_v< U >); 1719 | SA(!is_trivially_cmove_assignable_v< U >); 1720 | SA(!std::is_copy_assignable_v< U >); 1721 | SA(!is_vcopy_assignable_v< U >); 1722 | SA(!std::is_move_assignable_v< U >); 1723 | SA(!is_cmove_assignable_v< U >); 1724 | { 1725 | CONSTEXPR S s{}; 1726 | ASSERT (s.state_ == state::default_constructed); 1727 | CONSTEXPR U v{s}; 1728 | ASSERT (is_active< S >(v)); 1729 | ASSERT (static_cast< S const & >(v).state_ == state::copy_constructed); 1730 | ASSERT (s.state_ == state::default_constructed); 1731 | } 1732 | { 1733 | S s; 1734 | CHECK (s.state_ == state::default_constructed); 1735 | U v{s}; 1736 | CHECK (is_active< S >(v)); 1737 | CHECK (static_cast< S & >(v).state_ == state::vcopy_constructed); 1738 | CHECK (s.state_ == state::default_constructed); 1739 | } 1740 | { 1741 | CONSTEXPR S s{}; 1742 | ASSERT (s.state_ == state::default_constructed); 1743 | CONSTEXPR U v{std::move(s)}; 1744 | ASSERT (is_active< S >(v)); 1745 | ASSERT (static_cast< S const & >(v).state_ == state::copy_constructed); // `const &` operator win 1746 | ASSERT (s.state_ == state::default_constructed); 1747 | } 1748 | { 1749 | S s; 1750 | CHECK (s.state_ == state::default_constructed); 1751 | U v{std::move(s)}; 1752 | CHECK (is_active< S >(v)); 1753 | CHECK (static_cast< S & >(v).state_ == state::move_constructed); 1754 | CHECK (s.state_ == state::moved_from); 1755 | } 1756 | } 1757 | return true; 1758 | } 1759 | 1760 | CONSTEXPRF 1761 | static 1762 | bool 1763 | assignable() noexcept 1764 | { 1765 | struct S 1766 | { 1767 | state state_ = state::never_used; 1768 | CONSTEXPRF S() : state_{state::default_constructed} { ; } 1769 | CONSTEXPRF S(S const &) : state_{state::copy_constructed} { ; } 1770 | CONSTEXPRF S(S &) : state_{state::vcopy_constructed} { ; } 1771 | //CONSTEXPRF S(S const &&) { state_ = state::cmove_constructed; } 1772 | CONSTEXPRF S(S && s) : state_{state::move_constructed} { s.state_ = state::moved_from; } 1773 | CONSTEXPRF S & operator = (S const &) = default; 1774 | CONSTEXPRF S & operator = (S &) = default; 1775 | //CONSTEXPRF S & operator = (S const &&) { return *this; } 1776 | CONSTEXPRF S & operator = (S &&) = default; 1777 | //~S() DESTRUCTOR // clang bug: if destructor is user-declared and defaulted, then defaulted assignment operators become non-trivial and marked as non-constexpr 1778 | }; 1779 | SA(!std::is_trivially_copy_constructible_v< S >); 1780 | SA(!is_trivially_vcopy_constructible_v< S > ); 1781 | SA(!std::is_trivially_move_constructible_v< S >); 1782 | SA(!is_trivially_cmove_constructible_v< S > ); 1783 | SA(std::is_copy_constructible_v< S > ); 1784 | SA(is_vcopy_constructible_v< S > ); 1785 | SA(std::is_move_constructible_v< S > ); 1786 | SA(is_cmove_constructible_v< S > ); 1787 | SA(std::is_trivially_copy_assignable_v< S > ); 1788 | SA(!is_trivially_vcopy_assignable_v< S > ); // ? 1789 | SA(std::is_trivially_move_assignable_v< S > ); 1790 | SA(is_trivially_cmove_assignable_v< S > ); 1791 | SA(std::is_copy_assignable_v< S > ); 1792 | SA(is_vcopy_assignable_v< S > ); 1793 | SA(std::is_move_assignable_v< S > ); 1794 | SA(is_cmove_assignable_v< S > ); 1795 | struct N {}; 1796 | SA(std::is_trivial_v< N >); 1797 | { 1798 | using U = V< S, N >; 1799 | SA(!std::is_trivially_copy_constructible_v< U >); 1800 | SA(!is_trivially_vcopy_constructible_v< U >); // ? 1801 | SA(!std::is_trivially_move_constructible_v< U >); 1802 | SA(!is_trivially_cmove_constructible_v< U >); 1803 | SA(!std::is_copy_constructible_v< U >); 1804 | SA(!is_vcopy_constructible_v< U >); 1805 | SA(std::is_move_constructible_v< U >); // ? 1806 | SA(!is_cmove_constructible_v< U >); 1807 | SA(std::is_trivially_copy_assignable_v< U >); 1808 | SA(is_trivially_vcopy_assignable_v< U >); 1809 | SA(std::is_trivially_move_assignable_v< U >); 1810 | SA(is_trivially_cmove_assignable_v< U >); 1811 | SA(std::is_copy_assignable_v< U >); 1812 | SA(is_vcopy_assignable_v< U >); 1813 | SA(std::is_move_assignable_v< U >); 1814 | SA(is_cmove_assignable_v< U >); 1815 | { 1816 | CONSTEXPR S s{}; 1817 | ASSERT (s.state_ == state::default_constructed); 1818 | U v{}; 1819 | CHECK (is_active< S >(v)); 1820 | v = s; 1821 | CHECK (is_active< S >(v)); 1822 | CHECK (static_cast< S & >(v).state_ == state::copy_constructed); 1823 | ASSERT (s.state_ == state::default_constructed); 1824 | } 1825 | { 1826 | S s; 1827 | CHECK (s.state_ == state::default_constructed); 1828 | U v{}; 1829 | CHECK (is_active< S >(v)); 1830 | v = s; 1831 | CHECK (is_active< S >(v)); 1832 | CHECK (static_cast< S & >(v).state_ == state::vcopy_constructed); 1833 | CHECK (s.state_ == state::default_constructed); 1834 | } 1835 | { 1836 | CONSTEXPR S s{}; 1837 | ASSERT (s.state_ == state::default_constructed); 1838 | U v{}; 1839 | CHECK (is_active< S >(v)); 1840 | v = std::move(s); 1841 | CHECK (is_active< S >(v)); 1842 | CHECK (static_cast< S & >(v).state_ == state::copy_constructed); // `const &` operator win 1843 | ASSERT (s.state_ == state::default_constructed); 1844 | } 1845 | { 1846 | S s; 1847 | CHECK (s.state_ == state::default_constructed); 1848 | U v{}; 1849 | CHECK (is_active< S >(v)); 1850 | v = std::move(s); 1851 | CHECK (is_active< S >(v)); 1852 | CHECK (static_cast< S & >(v).state_ == state::move_constructed); 1853 | CHECK (s.state_ == state::moved_from); 1854 | } 1855 | } 1856 | { 1857 | using U = V< N, S >; 1858 | SA(!std::is_trivially_copy_constructible_v< U >); 1859 | SA(!is_trivially_vcopy_constructible_v< U >); 1860 | SA(!std::is_trivially_move_constructible_v< U >); 1861 | SA(!is_trivially_cmove_constructible_v< U >); 1862 | SA(!std::is_copy_constructible_v< U >); 1863 | SA(!is_vcopy_constructible_v< U >); 1864 | SA(std::is_move_constructible_v< U >); // ? 1865 | SA(!is_cmove_constructible_v< U >); 1866 | SA(std::is_trivially_copy_assignable_v< U >); 1867 | SA(is_trivially_vcopy_assignable_v< U >); 1868 | SA(std::is_trivially_move_assignable_v< U >); 1869 | SA(is_trivially_cmove_assignable_v< U >); 1870 | SA(std::is_copy_assignable_v< U >); 1871 | SA(is_vcopy_assignable_v< U >); 1872 | SA(std::is_move_assignable_v< U >); 1873 | SA(is_cmove_assignable_v< U >); 1874 | { 1875 | CONSTEXPR S s{}; 1876 | ASSERT (s.state_ == state::default_constructed); 1877 | U v{}; 1878 | CHECK (is_active< N >(v)); 1879 | v = s; 1880 | CHECK (is_active< S >(v)); 1881 | CHECK (static_cast< S & >(v).state_ == state::copy_constructed); 1882 | ASSERT (s.state_ == state::default_constructed); 1883 | } 1884 | { 1885 | S s; 1886 | CHECK (s.state_ == state::default_constructed); 1887 | U v{}; 1888 | CHECK (is_active< N >(v)); 1889 | v = s; 1890 | CHECK (is_active< S >(v)); 1891 | CHECK (static_cast< S & >(v).state_ == state::vcopy_constructed); 1892 | CHECK (s.state_ == state::default_constructed); 1893 | } 1894 | { 1895 | CONSTEXPR S s{}; 1896 | ASSERT (s.state_ == state::default_constructed); 1897 | U v{}; 1898 | CHECK (is_active< N >(v)); 1899 | v = std::move(s); 1900 | CHECK (is_active< S >(v)); 1901 | CHECK (static_cast< S & >(v).state_ == state::copy_constructed); // `const &` operator win 1902 | ASSERT (s.state_ == state::default_constructed); 1903 | } 1904 | { 1905 | S s; 1906 | CHECK (s.state_ == state::default_constructed); 1907 | U v{}; 1908 | CHECK (is_active< N >(v)); 1909 | v = std::move(s); 1910 | CHECK (is_active< S >(v)); 1911 | CHECK (static_cast< S & >(v).state_ == state::move_constructed); 1912 | CHECK (s.state_ == state::moved_from); 1913 | } 1914 | } 1915 | return true; 1916 | } 1917 | 1918 | CONSTEXPRF 1919 | static 1920 | bool 1921 | in_place_constructible() noexcept 1922 | { 1923 | using ::versatile::in_place; 1924 | using ::versatile::make_variant; 1925 | struct X {}; 1926 | struct Y {}; 1927 | { 1928 | struct A {}; 1929 | struct B {}; 1930 | using U = V< A, B >; 1931 | CONSTEXPR U a{in_place< A >}; 1932 | ASSERT (is_active< A >(a)); 1933 | CONSTEXPR U b{in_place< B >}; 1934 | ASSERT (is_active< B >(b)); 1935 | //CONSTEXPR auto d = make_variant< U >(); 1936 | //ASSERT (is_active< A >(d)); 1937 | } 1938 | { 1939 | struct A { A() = delete; }; 1940 | struct B {}; 1941 | using U = V< A, B >; 1942 | CONSTEXPR U b{in_place< B >}; 1943 | ASSERT (is_active< B >(b)); 1944 | CONSTEXPR auto d = make_variant< U >(); 1945 | ASSERT (is_active< B >(d)); 1946 | } 1947 | { 1948 | struct A { CONSTEXPRF A(X) { ; } }; 1949 | struct B { CONSTEXPRF B(Y) { ; } }; 1950 | using U = V< A, B >; 1951 | CONSTEXPR U a{in_place< A >, X{}}; 1952 | ASSERT (is_active< A >(a)); 1953 | CONSTEXPR U b{in_place< B >, Y{}}; 1954 | ASSERT (is_active< B >(b)); 1955 | CONSTEXPR auto x = make_variant< U >(X{}); 1956 | ASSERT (is_active< A >(x)); 1957 | CONSTEXPR auto y = make_variant< U >(Y{}); 1958 | ASSERT (is_active< B >(y)); 1959 | } 1960 | { 1961 | struct A { CONSTEXPRF A(X) { ; } }; 1962 | struct B { CONSTEXPRF B(X) { ; } }; 1963 | using U = V< A, B >; 1964 | CONSTEXPR U a{in_place< A >, X{}}; 1965 | ASSERT (is_active< A >(a)); 1966 | CONSTEXPR U b{in_place< B >, X{}}; 1967 | ASSERT (is_active< B >(b)); 1968 | CONSTEXPR auto x = make_variant< U >(X{}); 1969 | ASSERT (is_active< A >(x)); 1970 | } 1971 | { 1972 | struct B; 1973 | struct A { CONSTEXPRF A() = default; CONSTEXPRF A(B &&) { ; } }; 1974 | struct B { CONSTEXPRF B() = default; CONSTEXPRF B(A) { ; } }; 1975 | using U = V< A, B >; 1976 | CONSTEXPR U a{in_place< A >, B{}}; 1977 | ASSERT (is_active< A >(a)); 1978 | CONSTEXPR U b{in_place< B >, A{}}; 1979 | ASSERT (is_active< B >(b)); 1980 | CONSTEXPR auto x = make_variant< U >(B{}); 1981 | ASSERT (is_active< A >(x)); 1982 | CONSTEXPR auto y = make_variant< U >(A{}); 1983 | ASSERT (is_active< A >(y)); // move-constructed 1984 | } 1985 | { 1986 | struct A { CONSTEXPRF A(X, Y) { ; } }; 1987 | struct B { CONSTEXPRF B(Y, X) { ; } }; 1988 | using U = V< A, B >; 1989 | CONSTEXPR U a{in_place< A >, X{}, Y{}}; 1990 | ASSERT (is_active< A >(a)); 1991 | CONSTEXPR U b{in_place< B >, Y{}, X{}}; 1992 | ASSERT (is_active< B >(b)); 1993 | CONSTEXPR auto x = make_variant< U >(X{}, Y{}); 1994 | ASSERT (is_active< A >(x)); 1995 | CONSTEXPR auto y = make_variant< U >(Y{}, X{}); 1996 | ASSERT (is_active< B >(y)); 1997 | } 1998 | return true; 1999 | } 2000 | 2001 | CONSTEXPRF 2002 | static 2003 | bool 2004 | emplace() noexcept 2005 | { 2006 | using ::versatile::emplace; 2007 | struct X {}; 2008 | struct Y {}; 2009 | struct Z {}; 2010 | { 2011 | struct A { CONSTEXPRF A(X) { ; } }; 2012 | struct B { CONSTEXPRF B(Y) { ; } }; 2013 | using U = V< Z, A, B >; 2014 | U v{}; 2015 | CHECK (is_active< Z >(v)); 2016 | emplace< A >(v, X{}); 2017 | CHECK (is_active< A >(v)); 2018 | emplace< B >(v, Y{}); 2019 | CHECK (is_active< B >(v)); 2020 | emplace< Z >(v); 2021 | CHECK (is_active< Z >(v)); 2022 | } 2023 | { 2024 | struct A { CONSTEXPRF A(X) { ; } }; 2025 | struct B { CONSTEXPRF B(X) { ; } }; 2026 | using U = V< Z, A, B >; 2027 | U v{}; 2028 | CHECK (is_active< Z >(v)); 2029 | emplace< A >(v, X{}); 2030 | CHECK (is_active< A >(v)); 2031 | emplace< B >(v, X{}); 2032 | CHECK (is_active< B >(v)); 2033 | emplace< Z >(v); 2034 | CHECK (is_active< Z >(v)); 2035 | } 2036 | { 2037 | struct B; 2038 | struct A { CONSTEXPRF A() = default; CONSTEXPRF A(B &&) { ; } }; 2039 | struct B { CONSTEXPRF B() = default; CONSTEXPRF B(A) { ; } }; 2040 | using U = V< Z, A, B >; 2041 | U v{}; 2042 | CHECK (is_active< Z >(v)); 2043 | emplace< A >(v, B{}); 2044 | CHECK (is_active< A >(v)); 2045 | emplace< B >(v, A{}); 2046 | CHECK (is_active< B >(v)); 2047 | emplace< Z >(v); 2048 | CHECK (is_active< Z >(v)); 2049 | } 2050 | { 2051 | struct A { CONSTEXPRF A(X, Y) { ; } }; 2052 | struct B { CONSTEXPRF B(Y, X) { ; } }; 2053 | using U = V< Z, A, B >; 2054 | U v{}; 2055 | CHECK (is_active< Z >(v)); 2056 | emplace< A >(v, X{}, Y{}); 2057 | CHECK (is_active< A >(v)); 2058 | emplace< B >(v, Y{}, X{}); 2059 | CHECK (is_active< B >(v)); 2060 | emplace< Z >(v); 2061 | CHECK (is_active< Z >(v)); 2062 | } 2063 | return true; 2064 | } 2065 | 2066 | public : 2067 | 2068 | CONSTEXPRF 2069 | static 2070 | bool 2071 | run() noexcept 2072 | { 2073 | ASSERT (trivially_default_constructible()); 2074 | ASSERT (trivially_copy_move_constructible()); 2075 | ASSERT (trivially_copy_move_assignable()); 2076 | ASSERT (convertible()); // conversion 2077 | ASSERT (constructible()); // conversion 2078 | ASSERT (assignable()); // conversion 2079 | ASSERT (in_place_constructible()); 2080 | ASSERT (emplace()); 2081 | return true; 2082 | } 2083 | 2084 | }; 2085 | 2086 | template< template< typename ... > class wrapper, 2087 | template< typename ... > class versatile > 2088 | class check_utility 2089 | { 2090 | 2091 | template< typename ...types > 2092 | using V = versatile< typename wrapper< types >::type... >; 2093 | 2094 | CONSTEXPRF 2095 | static 2096 | bool 2097 | check_swap() noexcept 2098 | { 2099 | using std::swap; 2100 | { 2101 | struct A { int state; }; 2102 | struct B { int state; }; 2103 | using U = V< A, B >; 2104 | U a = A{1}; 2105 | CHECK (is_active< A >(a)); 2106 | U b = B{2}; 2107 | CHECK (is_active< B >(b)); 2108 | CHECK (static_cast< A & >(a).state == 1); 2109 | CHECK (static_cast< B & >(b).state == 2); 2110 | swap(a, b); 2111 | CHECK (is_active< A >(b)); 2112 | CHECK (is_active< B >(a)); 2113 | CHECK (static_cast< A & >(b).state == 1); 2114 | CHECK (static_cast< B & >(a).state == 2); 2115 | } 2116 | { 2117 | struct A { int state; }; 2118 | struct B {}; 2119 | using U = V< A, B >; 2120 | U x = A{1}; 2121 | CHECK (is_active< A >(x)); 2122 | U y = A{2}; 2123 | CHECK (is_active< A >(y)); 2124 | CHECK (static_cast< A & >(x).state == 1); 2125 | CHECK (static_cast< A & >(y).state == 2); 2126 | swap(x, y); 2127 | CHECK (is_active< A >(x)); 2128 | CHECK (is_active< A >(y)); 2129 | CHECK (static_cast< A & >(x).state == 2); 2130 | CHECK (static_cast< A & >(y).state == 1); 2131 | } 2132 | return true; 2133 | } 2134 | 2135 | CONSTEXPRF 2136 | static 2137 | bool 2138 | check_compare() noexcept 2139 | { 2140 | { 2141 | using U = V< int >; 2142 | CHECK(U{1} == U{1}); 2143 | CHECK(U{1} == 1); 2144 | CHECK(1 == U{1}); 2145 | } 2146 | { 2147 | using U = V< int >; 2148 | CHECK(U{1} < U{2}); 2149 | CHECK(!(U{2} < U{1})); 2150 | CHECK(U{1} < 2); 2151 | CHECK(!(U{2} < 1)); 2152 | CHECK(1 < U{2}); 2153 | CHECK(!(2 < U{1})); 2154 | } 2155 | { 2156 | using U = V< int >; 2157 | CHECK(!(U{1} < U{1})); 2158 | CHECK(!(U{1} < 1)); 2159 | CHECK(!(1 < U{1})); 2160 | } 2161 | return true; 2162 | } 2163 | 2164 | public : 2165 | 2166 | CONSTEXPRF 2167 | static 2168 | bool 2169 | run() noexcept 2170 | { 2171 | ASSERT (check_swap()); 2172 | ASSERT (check_swap()); 2173 | return true; 2174 | } 2175 | 2176 | }; 2177 | 2178 | } // namespace test 2179 | -------------------------------------------------------------------------------- /test/include/test/visit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test/prologue.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace test 12 | { 13 | 14 | template< typename F, std::size_t ...indices > 15 | struct enumerator 16 | { 17 | 18 | static constexpr std::size_t size_ = sizeof...(indices); 19 | static constexpr std::size_t count_ = (indices * ...); 20 | 21 | template< typename O, typename D > 22 | struct decomposer; 23 | 24 | template< std::size_t ...O, std::size_t ...D > 25 | struct decomposer< std::index_sequence< O... >, std::index_sequence< D... > > 26 | { 27 | 28 | F & f; 29 | 30 | static constexpr std::size_t indices_[size_] = {indices...}; 31 | 32 | static 33 | constexpr 34 | std::size_t 35 | order(std::size_t const i) noexcept 36 | { 37 | std::size_t o = 1; 38 | for (std::size_t n = i + 1; n < size_; ++n) { 39 | o *= indices_[n]; 40 | } 41 | return o; 42 | } 43 | 44 | static constexpr std::size_t orders_[size_] = {order(O)...}; 45 | 46 | static 47 | constexpr 48 | std::size_t 49 | digit(std::size_t d, std::size_t const o) noexcept 50 | { 51 | for (std::size_t n = 0; n < o; ++n) { 52 | d = d % orders_[n]; 53 | } 54 | return d / orders_[o]; 55 | } 56 | 57 | template< std::size_t d > 58 | using index_sequence = std::index_sequence< digit(d, O)... >; 59 | 60 | CONSTEXPRF 61 | bool 62 | operator () () const noexcept 63 | { 64 | return (f(index_sequence< D >{}) && ...); 65 | } 66 | 67 | }; 68 | 69 | decomposer< std::make_index_sequence< size_ >, std::make_index_sequence< count_ > > const decomposer_; 70 | 71 | CONSTEXPRF 72 | bool 73 | operator () () const noexcept 74 | { 75 | return decomposer_(); 76 | } 77 | 78 | }; 79 | 80 | template< std::size_t ...indices, typename F > 81 | CONSTEXPRF 82 | enumerator< F, indices... > 83 | make_enumerator(F & f) noexcept 84 | { 85 | SA(0 < sizeof...(indices)); 86 | SA(((0 < indices) && ...)); 87 | return {{f}}; 88 | } 89 | 90 | using ::versatile::type_qualifier; 91 | 92 | template< std::size_t M > 93 | struct pair 94 | { 95 | 96 | type_qualifier qual_ids[1 + M]; 97 | std::size_t type_ids[1 + M]; 98 | 99 | CONSTEXPRF 100 | bool 101 | operator == (pair const & _rhs) const noexcept 102 | { 103 | for (std::size_t i = 0; i <= M; ++i) { 104 | if (qual_ids[i] != _rhs.qual_ids[i]) { 105 | return false; 106 | } 107 | if (type_ids[i] != _rhs.type_ids[i]) { 108 | return false; 109 | } 110 | } 111 | return true; 112 | } 113 | 114 | CONSTEXPRF 115 | bool 116 | operator != (pair const & _rhs) const noexcept 117 | { 118 | return !operator == (_rhs); 119 | } 120 | 121 | CONSTEXPRF 122 | std::size_t 123 | size() const noexcept 124 | { 125 | return (1 + M); 126 | } 127 | 128 | }; 129 | 130 | using ::versatile::type_qualifier_of; 131 | 132 | template< std::size_t M, type_qualifier type_qual = type_qualifier::value > 133 | struct multivisitor 134 | { 135 | 136 | using result_type = pair< M >; 137 | 138 | result_type & result_; 139 | 140 | using return_type = ::versatile::add_type_qualifier_t< type_qual, result_type >; 141 | 142 | static constexpr type_qualifier type_qual_ = type_qual; 143 | 144 | CONSTEXPRF 145 | std::size_t 146 | which() const noexcept 147 | { 148 | return M; 149 | } 150 | 151 | template< typename ...types > 152 | CONSTEXPRF 153 | return_type 154 | operator () (types &&... _values) & noexcept 155 | { 156 | //ASSERT (M == sizeof...(types)); 157 | //ASSERT (!(is_visitable_v< types > || ...)); 158 | result_ = {{type_qualifier_of< multivisitor & >, type_qualifier_of< types && >...}, {which(), _values.get_state()...}}; 159 | return static_cast< return_type >(result_); 160 | } 161 | 162 | template< typename ...types > 163 | CONSTEXPRF 164 | return_type 165 | operator () (types &&... _values) const & noexcept 166 | { 167 | result_ = {{type_qualifier_of< multivisitor const & >, type_qualifier_of< types && >...}, {which(), _values.get_state()...}}; 168 | return static_cast< return_type >(result_); 169 | } 170 | 171 | template< typename ...types > 172 | CONSTEXPRF 173 | return_type 174 | operator () (types &&... _values) && noexcept 175 | { 176 | result_ = {{type_qualifier_of< multivisitor && >, type_qualifier_of< types && >...}, {which(), _values.get_state()...}}; 177 | return static_cast< return_type >(result_); 178 | } 179 | 180 | template< typename ...types > 181 | CONSTEXPRF 182 | return_type 183 | operator () (types &&... _values) const && noexcept 184 | { 185 | result_ = {{type_qualifier_of< multivisitor const && >, type_qualifier_of< types && >...}, {which(), _values.get_state()...}}; 186 | return static_cast< return_type >(result_); 187 | } 188 | 189 | }; 190 | 191 | template< typename array_type > 192 | struct subscripter 193 | { 194 | 195 | array_type & array_; 196 | 197 | constexpr 198 | array_type & 199 | operator () () const noexcept 200 | { 201 | return array_; 202 | } 203 | 204 | template< typename first, typename ...rest > 205 | constexpr 206 | decltype(auto) 207 | operator () (first const & _first, rest const &... _rest) const noexcept 208 | { 209 | return operator () (_rest...)[_first]; 210 | } 211 | 212 | }; 213 | 214 | template< typename array_type, typename ...indices > 215 | constexpr 216 | decltype(auto) 217 | subscript(array_type & _array, indices const &... _indices) noexcept 218 | { 219 | return subscripter< array_type >{_array}(_indices...); 220 | } 221 | 222 | constexpr auto type_qual_begin = static_cast< std::size_t >(type_qualifier_of< void * & >); 223 | constexpr auto type_qual_end = static_cast< std::size_t >(type_qualifier_of< void * volatile & >); 224 | 225 | template< typename multivisitor, typename variants, typename result_type > 226 | struct fusor 227 | { 228 | 229 | static constexpr std::size_t M = std::extent< variants >::value; 230 | 231 | template< typename = std::make_index_sequence< M > > 232 | struct fuse; 233 | 234 | template< std::size_t ...i > 235 | struct fuse< std::index_sequence< i... > > 236 | { 237 | 238 | multivisitor multivisitor_; 239 | variants variants_; 240 | std::size_t counter_; 241 | result_type result_; 242 | 243 | template< std::size_t m, std::size_t ...v > 244 | CONSTEXPRF 245 | bool 246 | operator () (std::index_sequence< m, v... >) noexcept 247 | { 248 | SA(M == sizeof...(v)); 249 | constexpr type_qualifier type_qual_m = static_cast< type_qualifier >(type_qual_begin + m); 250 | constexpr type_qualifier type_quals_v[sizeof...(v)] = {static_cast< type_qualifier >(type_qual_begin + v)...}; 251 | pair< M > const rhs = {{type_qual_m, type_quals_v[i]...}, {M, variants_[i].which()...}}; 252 | using ::versatile::forward_as; 253 | using ::versatile::multivisit; 254 | decltype(auto) lhs = multivisit(forward_as< type_qual_m >(multivisitor_), 255 | forward_as< type_quals_v[i] >(variants_[i])...); 256 | CHECK (type_qualifier_of< decltype(lhs) > == multivisitor_.type_qual_); 257 | CHECK (M + 1 == lhs.size()); 258 | if (!(lhs == rhs)) { 259 | return false; 260 | } 261 | bool & r = subscript(result_, m, v..., (variants_[i].which() - 1)...); 262 | if (r) { 263 | return false; 264 | } 265 | r = true; 266 | ++counter_; 267 | return true; 268 | } 269 | 270 | }; 271 | 272 | fuse<> fuse_; 273 | 274 | constexpr 275 | auto & 276 | operator [] (std::size_t const i) noexcept 277 | { 278 | return fuse_.variants_[i]; 279 | } 280 | 281 | }; 282 | 283 | template< typename value_type, std::size_t ...extents > 284 | struct multiarray; 285 | 286 | template< typename array_type > 287 | struct multiarray< array_type > 288 | { 289 | 290 | using type = array_type; 291 | 292 | }; 293 | 294 | template< typename type, std::size_t first, std::size_t ...rest > 295 | struct multiarray< type, first, rest... > 296 | : multiarray< type[first], rest... > 297 | { 298 | 299 | using value_type = type; 300 | 301 | }; 302 | 303 | template< typename value_type, std::size_t ...extents > 304 | using multiarray_t = typename multiarray< value_type, extents... >::type; 305 | 306 | constexpr std::size_t qual_count_ = (type_qual_end - type_qual_begin); 307 | 308 | // variant - variant 309 | // type - type generator 310 | // variant - variant template 311 | // wrapper - wrapper for alternative (bounded) types 312 | // M - multivisitor arity, N - number of alternative (bounded) types 313 | template< template< std::size_t I > class type, 314 | template< typename ...types > class variant, 315 | template< typename ...types > class wrapper, 316 | std::size_t M = 2, std::size_t N = M > 317 | class perferct_forwarding 318 | { 319 | 320 | template< type_qualifier type_qual, 321 | std::size_t ...i, std::size_t ...j > 322 | CONSTEXPRF 323 | static 324 | bool 325 | run(std::index_sequence< i... >, std::index_sequence< j... >) noexcept 326 | { 327 | using multivisitor_type = multivisitor< M, type_qual >; 328 | typename multivisitor_type::result_type result_{}; 329 | using variant_type = variant< typename wrapper< type< N - j > >::type... >; 330 | using result_type = multiarray_t< bool, qual_count_, (static_cast< void >(i), qual_count_)..., (static_cast< void >(i), N)... >; 331 | fusor< multivisitor_type, variant_type [M], result_type > fusor_{{{result_}, {}, 0, {}}}; 332 | auto const enumerator_ = make_enumerator< qual_count_, (static_cast< void >(i), qual_count_)... >(fusor_.fuse_); 333 | variant_type const variants_[N] = {type< N - j >{N - j}...}; 334 | CHECK (((variants_[j].which() == (N - j)) && ...)); 335 | std::size_t indices[M] = {}; 336 | for (;;) { 337 | ((fusor_[i] = variants_[indices[i]]), ...); 338 | if (!enumerator_()) { 339 | return false; 340 | } 341 | std::size_t m = 0; 342 | for (;;) { 343 | std::size_t & n = indices[m]; 344 | if (++n != N) { 345 | break; 346 | } 347 | n = 0; 348 | if (++m == M) { 349 | break; 350 | } 351 | } 352 | if (m == M) { 353 | break; 354 | } 355 | } 356 | constexpr std::size_t count_ = ((static_cast< void >(i), (N * qual_count_)) * ...) * qual_count_; // N ^ M * qual_count_ ^ (M + 1) 357 | CHECK (fusor_.fuse_.counter_ == count_); 358 | SA(sizeof(result_type) == count_ * sizeof(bool)); // sizeof(bool) is implementation-defined 359 | return true; 360 | } 361 | 362 | public : 363 | 364 | CONSTEXPRF 365 | static 366 | bool 367 | run() noexcept 368 | { 369 | constexpr auto i = std::make_index_sequence< M >{}; 370 | constexpr auto j = std::make_index_sequence< N >{}; 371 | CHECK (run< type_qualifier::value >(i, j)); 372 | CHECK (run< type_qualifier::const_value >(i, j)); 373 | CHECK (run< type_qualifier::lref >(i, j)); 374 | CHECK (run< type_qualifier::rref >(i, j)); 375 | CHECK (run< type_qualifier::const_lref >(i, j)); 376 | CHECK (run< type_qualifier::const_rref >(i, j)); 377 | return true; 378 | } 379 | 380 | }; 381 | 382 | } // namespace test 383 | -------------------------------------------------------------------------------- /test/include/test/wrappers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace test 7 | { 8 | 9 | template< typename type > 10 | struct aggregate 11 | : ::versatile::identity< ::versatile::aggregate_wrapper< type > > 12 | { 13 | 14 | }; 15 | 16 | template< typename type > 17 | struct recursive_wrapper 18 | : ::versatile::identity< ::versatile::recursive_wrapper< type > > 19 | { 20 | 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /test/src/boost_variant.cpp: -------------------------------------------------------------------------------- 1 | #include "test/boost_variant.hpp" 2 | #include "test/visit.hpp" 3 | 4 | #include 5 | 6 | int 7 | main() 8 | { 9 | using ::versatile::identity; 10 | using ::test::common_type; 11 | using ::test::perferct_forwarding; 12 | { // boost::variant 13 | { 14 | struct L {}; 15 | SA(std::is_literal_type_v< L >); 16 | SA(!std::is_literal_type_v< ::boost::variant< L > >); 17 | } 18 | using ::test_boost_variant::boost_variant_i; 19 | using ::test_boost_variant::boost_variant_c; 20 | using ::test_boost_variant::boost_recursive_wrapper; 21 | { 22 | CHECK ((perferct_forwarding< common_type, boost_variant_i, identity, 2, 2 >::run())); 23 | CHECK ((perferct_forwarding< common_type, boost_variant_i, boost_recursive_wrapper, 2, 2 >::run())); 24 | } 25 | { 26 | CHECK ((perferct_forwarding< common_type, boost_variant_c, identity, 2, 2 >::run())); 27 | CHECK ((perferct_forwarding< common_type, boost_variant_c, boost_recursive_wrapper, 2, 2 >::run())); 28 | } 29 | } 30 | return EXIT_SUCCESS; 31 | } 32 | -------------------------------------------------------------------------------- /test/src/eggs_variant.cpp: -------------------------------------------------------------------------------- 1 | #include "test/eggs_variant.hpp" 2 | #include "test/common.hpp" 3 | #include "test/visit.hpp" 4 | 5 | #include 6 | 7 | #include 8 | 9 | int 10 | main() 11 | { 12 | using ::versatile::identity; 13 | using ::test::literal_type; 14 | using ::test::common_type; 15 | using ::test::check_indexing; 16 | using ::test::check_destructible; 17 | using ::test::perferct_forwarding; 18 | { // eggs::variant 19 | using ::test_eggs_variant::eggs_variant_c; 20 | { 21 | ASSERT ((check_indexing< identity, eggs_variant_c >::run())); 22 | } 23 | { 24 | //CHECK ((check_destructible< identity, eggs_variant_c >::run())); // clang-3.8: fatal error: unable to execute command: Segmentation fault (core dumped) 25 | } 26 | { 27 | ASSERT ((perferct_forwarding< literal_type, eggs_variant_c, identity, 2, 2 >::run())); 28 | CHECK ((perferct_forwarding< common_type, eggs_variant_c, identity, 2, 2 >::run())); 29 | } 30 | } 31 | return EXIT_SUCCESS; 32 | } 33 | -------------------------------------------------------------------------------- /test/src/multivisit.cpp: -------------------------------------------------------------------------------- 1 | #include "test/versatile.hpp" 2 | #include "test/variant.hpp" 3 | #include "test/boost_variant.hpp" 4 | #include "test/eggs_variant.hpp" 5 | #include "test/common.hpp" 6 | #include "test/wrappers.hpp" 7 | #include "test/visit.hpp" 8 | 9 | #include 10 | 11 | int 12 | main() 13 | { 14 | using namespace ::versatile; 15 | using namespace ::test_boost_variant; 16 | { // multivisit mixed visitables 17 | struct A {}; 18 | struct B {}; 19 | 20 | struct 21 | { 22 | int operator () (A, A) { return 0; } 23 | int operator () (A, B) { return 1; } 24 | int operator () (B, A) { return 2; } 25 | int operator () (B, B) { return 3; } 26 | } v; 27 | 28 | A a; 29 | B b; 30 | 31 | using U = versatile< A, B >; 32 | using V = variant< A, B >; 33 | 34 | CHECK(multivisit(v, U{a}, V{a}) == 0); 35 | CHECK(multivisit(v, U{a}, V{b}) == 1); 36 | CHECK(multivisit(v, U{b}, V{a}) == 2); 37 | CHECK(multivisit(v, U{b}, V{b}) == 3); 38 | 39 | CHECK(multivisit(v, V{a}, U{a}) == 0); 40 | CHECK(multivisit(v, V{a}, U{b}) == 1); 41 | CHECK(multivisit(v, V{b}, U{a}) == 2); 42 | CHECK(multivisit(v, V{b}, U{b}) == 3); 43 | } 44 | { // adapted variants mixed multivisitation 45 | struct A {}; 46 | struct B {}; 47 | 48 | struct 49 | { 50 | int operator () (A, A) { return 0; } 51 | int operator () (A, B) { return 1; } 52 | int operator () (B, A) { return 2; } 53 | int operator () (B, B) { return 3; } 54 | } v; 55 | 56 | A a; 57 | B b; 58 | 59 | using U = boost_variant_c< A, B >; 60 | using V = boost_variant_i< A, B >; 61 | 62 | CHECK(multivisit(v, U{a}, V{a}) == 0); 63 | CHECK(multivisit(v, U{a}, V{b}) == 1); 64 | CHECK(multivisit(v, U{b}, V{a}) == 2); 65 | CHECK(multivisit(v, U{b}, V{b}) == 3); 66 | 67 | CHECK(multivisit(v, V{a}, U{a}) == 0); 68 | CHECK(multivisit(v, V{a}, U{b}) == 1); 69 | CHECK(multivisit(v, V{b}, U{a}) == 2); 70 | CHECK(multivisit(v, V{b}, U{b}) == 3); 71 | } 72 | return EXIT_SUCCESS; 73 | } 74 | -------------------------------------------------------------------------------- /test/src/test_ct_boost_variant.cpp: -------------------------------------------------------------------------------- 1 | #include "test/deep_and_hard.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace test 11 | { 12 | 13 | template< std::size_t ...M, std::size_t ...N > 14 | bool 15 | hard(std::index_sequence< M... >, std::index_sequence< N... >) noexcept 16 | { 17 | using V = ::boost::variant< T< M >... >; 18 | V variants_[sizeof...(N)] = {{T< (N % sizeof...(M)) >{}}...}; 19 | visitor< sizeof...(N) > visitor_; 20 | auto const rhs_ = apply_visitor(visitor_, variants_[N]...); 21 | decltype(rhs_) lhs_ = {{{N % sizeof...(M)}...}}; 22 | return ((lhs_[N] == rhs_[N]) && ...); 23 | } 24 | 25 | } 26 | 27 | #pragma clang diagnostic push 28 | #pragma clang diagnostic ignored "-Wpedantic" 29 | 30 | #if 4 < ROWS 31 | #undef ROWS 32 | #define ROWS 4 33 | #warning "ROWS is greater then 4, defaulted to 4" 34 | #endif 35 | 36 | #if 4 < COLS 37 | #undef COLS 38 | #define COLS 4 39 | #warning "COLS is greater then 4, defaulted to 4" 40 | #endif 41 | 42 | #pragma clang diagnostic pop 43 | 44 | int 45 | main() 46 | { 47 | CHECK ((test::run< ROWS, COLS >())); 48 | return EXIT_SUCCESS; 49 | } 50 | -------------------------------------------------------------------------------- /test/src/test_ct_eggs_variant.cpp: -------------------------------------------------------------------------------- 1 | #include "test/deep_and_hard.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace test 10 | { 11 | 12 | template< std::size_t ...M, std::size_t ...N > 13 | bool 14 | hard(std::index_sequence< M... >, std::index_sequence< N... >) noexcept 15 | { 16 | using V = ::eggs::variant< T< M >... >; 17 | V variants_[sizeof...(N)] = {{T< (N % sizeof...(M)) >{}}...}; 18 | visitor< sizeof...(N) > visitor_; 19 | auto const rhs_ = apply(visitor_, variants_[N]...); 20 | decltype(rhs_) lhs_ = {{{N % sizeof...(M)}...}}; 21 | return ((lhs_[N] == rhs_[N]) && ...); 22 | } 23 | 24 | } 25 | 26 | int 27 | main() 28 | { 29 | CHECK ((test::run< ROWS, COLS >())); 30 | return EXIT_SUCCESS; 31 | } 32 | -------------------------------------------------------------------------------- /test/src/test_ct_variant.cpp: -------------------------------------------------------------------------------- 1 | #include "test/deep_and_hard.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace test 10 | { 11 | 12 | template< std::size_t ...M, std::size_t ...N > 13 | bool 14 | hard(std::index_sequence< M... >, std::index_sequence< N... >) noexcept 15 | { 16 | using V = ::versatile::variant< T< M >... >; 17 | V variants_[sizeof...(N)] = {{T< (N % sizeof...(M)) >{}}...}; 18 | visitor< sizeof...(N) > visitor_; 19 | auto const rhs_ = multivisit(visitor_, variants_[N]...); 20 | decltype(rhs_) lhs_ = {{{N % sizeof...(M)}...}}; 21 | return ((lhs_[N] == rhs_[N]) && ...); 22 | } 23 | 24 | } 25 | 26 | int 27 | main() 28 | { 29 | CHECK ((test::run< ROWS, COLS >())); 30 | return EXIT_SUCCESS; 31 | } 32 | -------------------------------------------------------------------------------- /test/src/test_ct_versatile.cpp: -------------------------------------------------------------------------------- 1 | #include "test/deep_and_hard.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace test 10 | { 11 | 12 | template< std::size_t ...M, std::size_t ...N > 13 | bool 14 | hard(std::index_sequence< M... >, std::index_sequence< N... >) noexcept 15 | { 16 | using V = ::versatile::versatile< T< M >... >; 17 | V variants_[sizeof...(N)] = {{T< (N % sizeof...(M)) >{}}...}; 18 | visitor< sizeof...(N) > visitor_; 19 | auto const rhs_ = multivisit(visitor_, variants_[N]...); 20 | decltype(rhs_) lhs_ = {{{N % sizeof...(M)}...}}; 21 | return ((lhs_[N] == rhs_[N]) && ...); 22 | } 23 | 24 | } 25 | 26 | int 27 | main() 28 | { 29 | CHECK ((test::run< ROWS, COLS >())); 30 | return EXIT_SUCCESS; 31 | } 32 | -------------------------------------------------------------------------------- /test/src/traits.cpp: -------------------------------------------------------------------------------- 1 | #include "test/traits.hpp" 2 | 3 | #include 4 | 5 | int 6 | main() 7 | { 8 | return EXIT_SUCCESS; 9 | } 10 | -------------------------------------------------------------------------------- /test/src/variant.cpp: -------------------------------------------------------------------------------- 1 | #include "test/variant.hpp" 2 | #include "test/common.hpp" 3 | #include "test/wrappers.hpp" 4 | #include "test/visit.hpp" 5 | 6 | #include 7 | 8 | int 9 | main() 10 | { 11 | using ::versatile::identity; 12 | using ::test::aggregate; 13 | using ::test::recursive_wrapper; 14 | using ::test::common_type; 15 | using ::test::check_indexing; 16 | using ::test::check_common; 17 | using ::test::check_destructible; 18 | using ::test::check_runtime; 19 | using ::test::perferct_forwarding; 20 | { // variant 21 | using ::versatile::variant; 22 | { 23 | CHECK ((check_indexing< identity, variant >::run())); 24 | CHECK ((check_indexing< aggregate, variant >::run())); 25 | //CHECK ((check_indexing< recursive_wrapper, variant >::run())); 26 | } 27 | { 28 | CHECK ((check_common< identity, variant >::run())); 29 | CHECK ((check_common< aggregate, variant >::run())); 30 | //CHECK ((check_common< recursive_wrapper, variant >::run())); 31 | } 32 | { 33 | CHECK ((check_destructible< identity, variant >::run())); 34 | CHECK ((check_destructible< aggregate, variant >::run())); 35 | //CHECK ((check_destructible< recursive_wrapper, variant >::run())); 36 | } 37 | { 38 | CHECK ((check_runtime< variant >::run())); 39 | } 40 | { 41 | CHECK ((perferct_forwarding< common_type, variant, identity, 2, 2 >::run())); 42 | CHECK ((perferct_forwarding< common_type, variant, aggregate, 2, 2 >::run())); 43 | CHECK ((perferct_forwarding< common_type, variant, recursive_wrapper, 2, 2 >::run())); 44 | } 45 | } 46 | return EXIT_SUCCESS; 47 | } 48 | -------------------------------------------------------------------------------- /test/src/versatile.cpp: -------------------------------------------------------------------------------- 1 | #include "test/versatile.hpp" 2 | #include "test/common.hpp" 3 | #include "test/wrappers.hpp" 4 | #include "test/visit.hpp" 5 | 6 | #include 7 | 8 | int 9 | main() 10 | { 11 | using ::versatile::identity; 12 | using ::test::aggregate; 13 | using ::test::recursive_wrapper; 14 | using ::test::literal_type; 15 | using ::test::check_indexing; 16 | using ::test::check_invariants; 17 | using ::test::check_triviality; 18 | using ::test::check_utility; 19 | using ::test::check_destructible; 20 | using ::test::perferct_forwarding; 21 | { // versatile 22 | using ::versatile::versatile; 23 | { 24 | ASSERT ((check_indexing< identity, versatile >::run())); 25 | ASSERT ((check_indexing< aggregate, versatile >::run())); 26 | //CHECK ((check_indexing< recursive_wrapper, versatile >::run())); 27 | } 28 | { 29 | ASSERT ((check_invariants< identity, versatile >::run())); 30 | ASSERT ((check_invariants< aggregate, versatile >::run())); 31 | } 32 | { 33 | ASSERT ((check_triviality< identity, versatile >::run())); 34 | ASSERT ((check_triviality< aggregate, versatile >::run())); 35 | } 36 | { 37 | ASSERT ((check_utility< identity, versatile >::run())); 38 | ASSERT ((check_utility< aggregate, versatile >::run())); 39 | } 40 | { 41 | CHECK ((check_destructible< identity, versatile >::run())); 42 | CHECK ((check_destructible< aggregate, versatile >::run())); 43 | CHECK ((check_destructible< recursive_wrapper, versatile >::run())); 44 | } 45 | { 46 | ASSERT ((perferct_forwarding< literal_type, versatile, identity, 2, 2 >::run())); 47 | ASSERT ((perferct_forwarding< literal_type, versatile, aggregate, 2, 2 >::run())); 48 | } 49 | } 50 | return EXIT_SUCCESS; 51 | } 52 | --------------------------------------------------------------------------------