Я экспериментирую с Прото построить DSEL который работает на геометрических векторах. Я пытаюсь написать преобразование, которое бы взяло выражение для присваивания и развернуло его по компонентам. Например, я хочу заменить
p = q + r;
от
p[0] = q[0] + r[0],
p[1] = q[1] + r[1],
...,
p[N] = q[N] + r[N],
p;
До сих пор я был в состоянии в основном заставить его работать, сделав шаблон преобразования unroll_vector_expr
который рекурсивно разворачивает выражение для каждого компонента вектора, в сочетании с distribute_subscript
преобразования.
Кажется, я не понимаю, в чем смысл «параметров», используемых с boost::result_of
а также result_of::make_expr
, Документация, примеры и внутренний код кажутся смешанными Expr
, impl::expr
а также impl::expr_param
, Я не уверен, что я должен использовать и когда так, чтобы result_type
соответствует фактическому типу результата. В настоящее время я заставил это работать пробной ошибкой, исследуя сообщения об ошибках и исправляя const
а также &
расхождения. Однако, как только я глубоко скопировал выражение, терминалы перестали удерживаться ссылкой, и мой код дал сбой.
struct distribute_subscript
: or_<
scalar_grammar
, when<
vector_literal
, _make_subscript( _, _state )
>
, plus< distribute_subscript, distribute_subscript >
, minus< distribute_subscript, distribute_subscript >
, multiplies< distribute_subscript, distribute_subscript >
, divides< distribute_subscript, distribute_subscript >
, assign< distribute_subscript, distribute_subscript >
>
{};
template< std::size_t I, std::size_t N >
struct unroll_vector_expr_c;
template< std::size_t I, std::size_t N >
struct unroll_vector_expr_c
: transform< unroll_vector_expr_c< I, N > >
{
template< typename Expr, typename State, typename Data >
struct impl
: transform_impl< Expr, State, Data >
{
typedef
typename result_of::make_expr<
tag::comma
, typename boost::result_of<
distribute_subscript(
Expr
, typename result_of::make_expr<
tag::terminal
, boost::mpl::size_t< I - 1 >
>::type
)
>::type
, typename boost::result_of<
unroll_vector_expr_c< I + 1, N >(
Expr
)
>::type
>::type
result_type;
result_type operator ()(
typename impl::expr_param expr
, typename impl::state_param state
, typename impl::data_param data
) const
{
return
make_expr< tag::comma >(
distribute_subscript()(
expr
, make_expr< tag::terminal >(
boost::mpl::size_t< I - 1 >()
)
)
, unroll_vector_expr_c< I + 1, N >() (
expr
)
);
}
};
};
template< std::size_t N >
struct unroll_vector_expr_c< N, N >
: transform< unroll_vector_expr_c< N, N > >
{
template< typename Expr, typename State, typename Data >
struct impl
: transform_impl< Expr, State, Data >
{
typedef
typename boost::result_of<
distribute_subscript(
Expr
, typename result_of::make_expr<
tag::terminal
, boost::mpl::size_t< N - 1 >
>::type
)
>::type
result_type;
result_type operator ()(
typename impl::expr_param expr
, typename impl::state_param state
, typename impl::data_param data
) const
{
return
distribute_subscript()(
expr
, make_expr< tag::terminal >(
boost::mpl::size_t< N - 1 >()
)
);
}
};
};
struct unroll_vector_expr
: transform< unroll_vector_expr >
{
template< typename Expr, typename State, typename Data >
struct impl
: transform_impl< Expr, State, Data >
{
typedef
typename dimension<
typename boost::remove_reference<
typename boost::result_of<
_value( State )
>::type
>::type
>::type
dimension;
typedef
typename result_of::make_expr<
tag::comma
, typename boost::result_of<
unroll_vector_expr_c< 1, dimension::value >(
Expr
)
>::type
, State
>::type
result_type;
result_type operator ()(
typename impl::expr_param expr
, typename impl::state_param state
, typename impl::data_param data
) const
{
return
make_expr< tag::comma >(
unroll_vector_expr_c< 1, dimension::value >()(
expr
)
, boost::ref( state )
);
}
};
};
Как мне написать свое преобразование, чтобы result_type
соответствует результат из operator ()
и работает на terminal
Оба держат по значению и по ссылке?
Обновить: Код обновлен после Эрикответ. Единственное оставшееся несоответствие между result_type
а также make_expr
для первый создание unroll_vector_expr_c
, где terminal< mpl::size_t< 0 > >::type
проводится постоянная ссылка вместо значение. Любопытно, что последующие экземпляры одного и того же шаблона с более высокими индексами не приводят к этой проблеме.
Обновить: Мне удалось заставить код полностью работать после изменения distribue_subscript
transform, чтобы заставить взять индекс индекса по значению:
struct distribute_subscript
: or_<
scalar_grammar
, when<
vector_literal
, _make_subscript( _, _byval( _state ) ) // <-- HERE
>
, plus< distribute_subscript, distribute_subscript >
, minus< distribute_subscript, distribute_subscript >
, multiplies< distribute_subscript, distribute_subscript >
, divides< distribute_subscript, distribute_subscript >
, assign< distribute_subscript, distribute_subscript >
>
{};
Быстрый ответ на данный момент. Я постараюсь более внимательно посмотреть на ваше преобразование завтра.
Значение impl::expr
а также impl::expr_param
можно понять, посмотрев на документацию для transform_impl
. Короче говоря, используйте impl::expr_param
в подписи вашего преобразования operator()
, поскольку он добавляет const &
чтобы выражения не копировались при передаче вашей функции. использование Expr
в ваших вычислениях типа, как в boost::result_of
, impl::expr
не очень полезен и может быть проигнорирован.
Что касается deep_copy
всегда заставляя ваши терминалы удерживаться на значении, это почти то, что deep_copy
для. Но, может быть, вы имеете в виду что-то еще, так как я не вижу deep_copy
в вашем коде где угодно.
Слово о make_expr
: заставляет задуматься очень осторожно о том, какие узлы должны храниться по ссылке, а какие по значению. В вычислении типа (result_of::make_expr
), ссылочные типы — это то, что должно храниться по ссылке, но при фактическом вызове функции (proto::make_expr
), вы должны обернуть вещи с boost::ref
если хотите то держите по ссылке. Это странно Проверьте пользовательские документы на make_expr
.
Других решений пока нет …