diff --git a/detail/default_eval.hpp b/detail/default_eval.hpp index abebbf1..8f1c6d4 100644 --- a/detail/default_eval.hpp +++ b/detail/default_eval.hpp @@ -156,6 +156,9 @@ namespace boost::proto17 { } } + template + auto transform_nonterminal_tuple (Tuple && tuple, Transform && transform); + template > struct default_transform_expression { @@ -163,17 +166,12 @@ namespace boost::proto17 { { constexpr expr_kind kind = kind_of>::value; if constexpr (kind == expr_kind::terminal || kind == expr_kind::placeholder) { - return expr; + return static_cast(expr); } else { - auto tuple = hana::transform( - expr.elements, - [&transform](auto && element) { - default_transform_expression transformer; - return transformer(element, static_cast(transform)); - } + return transform_nonterminal_tuple( + static_cast(expr.elements), + static_cast(transform) ); - using return_type = typename expression_from_tuple::type; - return return_type(std::move(tuple)); } } }; @@ -189,6 +187,24 @@ namespace boost::proto17 { { return static_cast(transform)(static_cast(expr)); } }; + template + auto transform_nonterminal_tuple (Tuple && tuple, Transform && transform) + { + auto transformed_tuple = hana::transform( + static_cast(tuple), + [&transform](auto && element) { + using element_t = decltype(element); + default_transform_expression transformer; + return transformer( + static_cast(element), + static_cast(transform) + ); + } + ); + using return_type = typename expression_from_tuple::type; + return return_type(std::move(transformed_tuple)); + } + } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4e34343..adc43ef 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,4 +41,6 @@ add_executable( compile_x_plus_term.cpp compile_term_plus_x_this_ref_overloads.cpp compile_const_term.cpp + compile_move_only_types.cpp + # ICE! compile_copy_only_types.cpp ) diff --git a/test/compile_copy_only_types.cpp b/test/compile_copy_only_types.cpp new file mode 100644 index 0000000..ce01379 --- /dev/null +++ b/test/compile_copy_only_types.cpp @@ -0,0 +1,47 @@ +#include "expression.hpp" + +#include + +template +using term = boost::proto17::terminal; + +namespace bp17 = boost::proto17; + + +namespace { + +auto double_to_float (term expr) +{ return term{(float)expr.value()}; } + +struct copy_only_t +{ + copy_only_t (copy_only_t &&) = delete; + copy_only_t & operator= (copy_only_t &&) = delete; + + int value; +}; + +void compile() +{ + term unity{1}; + term d{3.5}; + bp17::expression< + bp17::expr_kind::plus, + term, + term + > expr_1 = unity + d; + + bp17::expression< + bp17::expr_kind::plus, + term, + bp17::expression< + bp17::expr_kind::plus, + term, + term + > + > expr_2 = unity + expr_1; + + auto transformed_expr = transform(expr_2, double_to_float); +} + +} diff --git a/test/compile_move_only_types.cpp b/test/compile_move_only_types.cpp new file mode 100644 index 0000000..833049c --- /dev/null +++ b/test/compile_move_only_types.cpp @@ -0,0 +1,39 @@ +#include "expression.hpp" + +#include + +template +using term = boost::proto17::terminal; + +namespace bp17 = boost::proto17; + + +namespace { + +auto double_to_float (term expr) +{ return term{(float)expr.value()}; } + +void compile() +{ + term unity{1.0}; + term> i{new int{7}}; + bp17::expression< + bp17::expr_kind::plus, + term, + term> + > expr_1 = unity + std::move(i); + + bp17::expression< + bp17::expr_kind::plus, + term, + bp17::expression< + bp17::expr_kind::plus, + term, + term> + > + > expr_2 = unity + std::move(expr_1); + + auto transformed_expr = transform(std::move(expr_2), double_to_float); +} + +} diff --git a/test/user_expression_transform_3.cpp b/test/user_expression_transform_3.cpp index c6250b9..924d64f 100644 --- a/test/user_expression_transform_3.cpp +++ b/test/user_expression_transform_3.cpp @@ -2,8 +2,6 @@ #include -#include - template using term = boost::proto17::terminal; @@ -25,9 +23,6 @@ namespace user { friend number operator* (number lhs, number rhs) { return number{lhs.value * rhs.value}; } - - friend std::ostream & operator<< (std::ostream & os, number x) // TODO - { return os << x.value; } }; number naxpy (number a, number x, number y) @@ -103,11 +98,6 @@ namespace user { } -// TODO: Add a unit test for moved expressions and expressions containing -// move-only types or rvalue refs. - -// TODO: Use move-only type in other tests that test moves as well. - TEST(user_expression_transform_3, test_user_expression_transform_3) { term a{{1.0}}; @@ -211,3 +201,38 @@ TEST(user_expression_transform_3, test_user_expression_transform_3) } } } + +auto double_to_float (term expr) +{ return term{(float)expr.value()}; } + +auto check_unique_ptrs_equal_7 (term> && expr) +{ + using namespace boost::hana::literals; + EXPECT_EQ(*expr.elements[0_c], 7); + return std::move(expr); +} + +TEST(move_only, test_user_expression_transform_3) +{ + term unity{1.0}; + term> i{new int{7}}; + bp17::expression< + bp17::expr_kind::plus, + term, + term> + > expr_1 = unity + std::move(i); + + bp17::expression< + bp17::expr_kind::plus, + term, + bp17::expression< + bp17::expr_kind::plus, + term, + term> + > + > expr_2 = unity + std::move(expr_1); + + auto transformed_expr = transform(std::move(expr_2), double_to_float); + + transform(std::move(transformed_expr), check_unique_ptrs_equal_7); +}