/// \file meta.cpp Tests for Meta: a tiny metaprogramming library // Meta: a tiny metaprogramming library // // Copyright Eric Niebler 2013-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Acknowledgements: Thanks for Paul Fultz for the suggestions that // concepts can be ordinary Boolean metafunctions. // // Project home: https://github.com/ericniebler/range-v3 // #include #include #include "../simple_test.hpp" using namespace meta; // An implementation of tuple_cat gives Range v3's meta-programming and list // utilities a good workout. It's a good compiler stress test, too. namespace tc_detail { template Ret tuple_cat_(list, list, Tuples tpls) { return Ret{std::get(std::get(tpls))...}; } } template, concat...>>> Res tuple_cat(Tuples &&... tpls) { static constexpr std::size_t N = sizeof...(Tuples); // E.g. [0,0,0,2,2,2,3,3] using inner = join< transform...>, transform>, quote>, quote>>; // E.g. [0,1,2,0,1,2,0,1] using outer = join< transform...>, compose, quote_i, quote>>>; return tc_detail::tuple_cat_(inner{}, outer{}, std::forward_as_tuple(std::forward(tpls)...)); } void test_tuple_cat() { std::tuple t1; std::tuple<> t2; std::tuple t3; std::tuple t4; auto x = ::tuple_cat(t1, t2, t3, t4); using expected_type = std::tuple; static_assert(std::is_same::value, ""); } // Other misc tests static_assert(std::is_same>, list>::value, ""); static_assert(std::is_same>, list>::value, ""); static_assert(std::is_same>, list>::value, ""); static_assert(all_of, quote>::value, ""); static_assert(none_of, quote>::value, ""); static_assert(!any_of, quote>::value, ""); static_assert(any_of, quote>::value, ""); static_assert(std::is_same>>, std::tuple>, list>::value, ""); template struct can_invoke_ : std::false_type { }; template struct can_invoke_, meta::void_>> : std::true_type { }; template struct can_invoke : can_invoke_> { }; static_assert(can_invoke, int, int>::value, ""); // I'm guessing this failure is due to GCC #64970 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970 #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5 static_assert(!can_invoke, int, int, int>::value, ""); #endif // Sanity-check meta::lambda using Lambda0 = lambda<_a, _b, std::pair<_a, _b>>; using Lambda1 = lambda<_a, _b, std::pair<_b, _a>>; using Lambda2 = lambda<_a, _b, std::pair<_b, std::pair<_a, _a>>>; using Pair0 = invoke; using Pair1 = invoke; using Pair2 = invoke; static_assert(std::is_same>::value, ""); static_assert(std::is_same>::value, ""); static_assert(std::is_same>>::value, ""); // Not saying you should do it this way, but it's a good test. namespace l = meta::lazy; template using cart_prod = reverse_fold< L, list>, lambda< _a, _b, l::join>>>>>>>>>; using CartProd = cart_prod, meta::list>>; static_assert( std::is_same, meta::list, meta::list, meta::list>>::value, ""); static_assert(can_invoke, _a>>, int>::value, ""); // I'm guessing this failure is due to GCC #64970 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970 #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5 static_assert(!can_invoke, _a>>, float>::value, ""); #endif template using rev = reverse_fold, lambda<_a, _b, defer>>; static_assert(std::is_same>, list>::value, ""); using uncvref_fn = lambda<_a, l::_t>>>>; static_assert(std::is_same, int>::value, ""); using L = list; static_assert(std::is_same, list>::value, ""); static_assert(std::is_same, int>>, list>::value, ""); static_assert(std::is_same, double>>, list<>>::value, ""); static_assert(std::is_same, list>::value, ""); static_assert(std::is_same, int>>, list>::value, ""); static_assert(std::is_same, double>>, list<>>::value, ""); struct check_integral { template constexpr T operator()(T &&i) const { static_assert(std::is_integral{}, ""); return i; } }; // Test for meta::let template using find_index_ = let< var<_a, List>, var<_b, lazy::find<_a, T>>, lazy::if_>, meta::npos, lazy::minus, lazy::size<_b>>>>; static_assert(find_index_>{} == 1, ""); static_assert(find_index_>{} == meta::npos{}, ""); // Test that the unselected branch does not get evaluated: template using test_lazy_if_ = let, T, defer>>; static_assert(std::is_same, void>::value, ""); // Test that and_ gets short-circuited: template using test_lazy_and_ = let, defer>>; static_assert(std::is_same, std::false_type>::value, ""); // Test that and_ gets short-circuited: template using test_lazy_or_ = let, defer>>; static_assert(std::is_same, std::true_type>::value, ""); template struct lambda_test { }; template struct fact : let 0), lazy::multiplies>>, meta::size_t<1>>> { }; static_assert(fact>::value == 1, ""); static_assert(fact>::value == 1, ""); static_assert(fact>::value == 2, ""); static_assert(fact>::value == 6, ""); static_assert(fact>::value == 24, ""); template struct fact2 : let 0), lazy::multiplies, defer_i>, meta::size_t<1>>> { }; static_assert(fact2<0>::value == 1, ""); static_assert(fact2<1>::value == 1, ""); static_assert(fact2<2>::value == 2, ""); static_assert(fact2<3>::value == 6, ""); static_assert(fact2<4>::value == 24, ""); template struct factorial : let, lazy::multiplies>>>> { }; static_assert(factorial>::value == 1, ""); static_assert(factorial>::value == 1, ""); static_assert(factorial>::value == 2, ""); static_assert(factorial>::value == 6, ""); static_assert(factorial>::value == 24, ""); int main() { // meta::sizeof_ static_assert(meta::sizeof_{} == sizeof(int), ""); // meta::min static_assert(meta::min, meta::size_t<1>>{} == 0, ""); static_assert(meta::min, meta::size_t<0>>{} == 0, ""); static_assert(meta::min, meta::size_t<0>>{} == 0, ""); // meta::max static_assert(meta::max, meta::size_t<1>>{} == 1, ""); static_assert(meta::max, meta::size_t<0>>{} == 1, ""); static_assert(meta::max, meta::size_t<1>>{} == 1, ""); // meta::filter { using l = meta::list; using il = meta::list; using fl = meta::list; static_assert(std::is_same>>{}, ""); static_assert(std::is_same>>{}, ""); } // meta::for_each { using l = meta::list; constexpr auto r = meta::for_each(l{}, check_integral()); static_assert(std::is_same>, check_integral>::value, ""); } // meta::find_index { using l = meta::list; static_assert(meta::find_index{} == 0, ""); static_assert(meta::find_index{} == 1, ""); static_assert(meta::find_index{} == 2, ""); static_assert(meta::find_index{} == meta::npos{}, ""); static_assert(meta::find_index{} == meta::npos{}, ""); using l2 = meta::list<>; static_assert(meta::find_index{} == meta::npos{}, ""); using namespace meta::placeholders; using lambda = meta::lambda<_a, _b, meta::lazy::find_index<_b, _a>>; using result = meta::invoke; static_assert(result{} == 1, ""); } // meta::reverse_find_index { using l = meta::list; static_assert(meta::reverse_find_index{} == 3, ""); static_assert(meta::reverse_find_index{} == 1, ""); static_assert(meta::reverse_find_index{} == 2, ""); static_assert(meta::reverse_find_index{} == meta::npos{}, ""); static_assert(meta::reverse_find_index{} == meta::npos{}, ""); using l2 = meta::list<>; static_assert(meta::reverse_find_index{} == meta::npos{}, ""); using lambda = meta::lambda<_a, _b, meta::lazy::reverse_find_index<_b, _a>>; using result = meta::invoke; static_assert(result{} == 1, ""); } // meta::count { using l = meta::list; static_assert(meta::count{} == 2, ""); static_assert(meta::count{} == 1, ""); static_assert(meta::count{} == 0, ""); } // meta::count_if { using l = meta::list; static_assert(meta::count_if>>{} == 2, ""); static_assert(meta::count_if>>{} == 1, ""); static_assert(meta::count_if>>{} == 0, ""); } // pathological lambda test { using X = invoke>, int>; static_assert(std::is_same>::value, ""); } // meta::unique { using l = meta::list; static_assert(std::is_same, list>::value, ""); } // meta::in { static_assert(in, int>::value, ""); static_assert(in, short>::value, ""); static_assert(in, float>::value, ""); static_assert(!in, double>::value, ""); } // lambda with variadic placeholders { using X = invoke>, int, short, double>; static_assert(std::is_same>::value, ""); using X2 = invoke>, int>; static_assert(std::is_same>::value, ""); using Y = invoke>, int, short>; static_assert(std::is_same>::value, ""); using Y2 = invoke>>, int, short>; static_assert(std::is_same>>::value, ""); using Z = invoke>, short *, short, float>; static_assert(std::is_same>::value, ""); // Nesting variadic lambdas in non-variadic lambdas: using A = invoke>, _a, lazy::_t>, lazy::_t>>>, int>; static_assert(std::is_same>::value, ""); // Nesting non-variadic lambdas in variadic lambdas: using B = invoke>, _a>>, int, short, double>; static_assert(std::is_same>::value, ""); // Nesting variadic lambdas in variadic lambdas: using ZZ = invoke< lambda<_a, _args_a, lazy::invoke, list<_args_a>>>, _args_a>>, int, short, float, double>; static_assert( std::is_same, list>>::value, ""); // I'm guessing this failure is due to GCC #64970 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970 #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5 static_assert(!can_invoke>, int>::value, ""); static_assert(!can_invoke>, int, short, double>::value, ""); static_assert(!can_invoke>, int, short>::value, ""); static_assert(!can_invoke>>::value, ""); #endif } // Test for meta::sort { using L0 = list; using L2 = meta::sort, lazy::sizeof_<_b>>>>; static_assert( std::is_same< L2, list>::value, ""); } // Check the _z user-defined literal: static_assert(42_z == 42, ""); // Check integer_range { constexpr std::size_t a = meta::fold>, meta::size_t<0>, meta::quote>{}; static_assert(a == 10, ""); constexpr std::size_t b = meta::fold>, meta::size_t<0>, meta::quote>{}; static_assert(b == 35, ""); constexpr std::size_t c = meta::fold>, meta::size_t<0>, meta::quote>{}; static_assert(c == 190, ""); using d = meta::integer_range; static_assert(std::is_same>{}, ""); } // Check reverse_fold { constexpr std::size_t a = meta::reverse_fold>, meta::size_t<0>, meta::quote>{}; static_assert(a == 10, ""); constexpr std::size_t b = meta::reverse_fold>, meta::size_t<0>, meta::quote>{}; static_assert(b == 35, ""); constexpr std::size_t c = meta::reverse_fold>, meta::size_t<0>, meta::quote>{}; static_assert(c == 190, ""); } test_tuple_cat(); return ::test_result(); }