Как мне написать протопреобразование на основе функции?
Я хотел бы повторно использовать код, написав протопреобразование, которое шаблонируется указателем на функцию:
template <typename Ret, typename A0, typename A1, Ret func(A0,A1)>
struct apply_func : proto::callable
{
// Do something with func
};
Однако сама функция полиморфна, поэтому я не хочу указывать ее точную подпись.
Ниже приведена упрощенная версия того, как должен выглядеть мой код (я использую внешние преобразования по технической причине, которая, по-моему, не связана с моим текущим вопросом - я не смог заставить рекурсию работать без них):
template<typename R, typename A0, typename A1>
R plus_func(A0 lhs, A1 rhs) { return lhs+rhs; }
template<typename R, typename A0, typename A1>
R minus_func(A0 lhs, A1 rhs) { return lhs-rhs; }
struct my_grammar;
struct plus_rule : proto::plus<my_grammar, my_grammar> {};
struct minus_rule : proto::minus<my_grammar, my_grammar> {};
struct my_grammar
: proto::or_<
proto::when<proto::terminal<proto::_>, proto::_value>
, proto::when<plus_rule, proto::external_transform >
, proto::when<minus_rule, proto::external_transform >
>
{};
struct my_external_transforms
: proto::external_transforms<
proto::when<plus_rule, apply_func<plus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)>
, proto::when<minus_rule, apply_func<minus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)>
>
{};
Это не компилируется, потому что в шаблоне appy_func отсутствуют аргументы. Есть ли решение?
1 ответ
У вас есть несколько проблем в вашем коде:
- Вы не можете взять указатель на функцию шаблона, не указав ее параметр шаблона, так как шаблон не будет существовать до тех пор, пока функция не будет создана.
- вторая точка, Ret(A,B) - это тип функции, а не тип указателя на функцию.
- указатель на функцию является немного необработанным в процессе абстракции, то же самое может быть достигнуто с помощью функтора, который также решает вашу проблему, так как полиморфный объект-функция представляет собой один тип, не являющийся шаблоном.
- И, наконец, техническая точка: шаблонное преобразование не может использовать proto::callable, вы должны явно специализировать boost::proto::is_callable. Это связано с языковым ограничением того, как обнаруживается наследование.
Просматривая ваш псевдокод, я пойду на что-то вроде:
struct plus_func
{
template<class Sig> struct result;
template<class This,class A, class B>
struct result<This(A,B)>
{
typedef /*whatever*/ type;
};
template<class A, class B>
typename result<plus_func(A const&,B const&)>::type
plus_func(A const& lhs, B const& rhs)
{
return lhs+rhs;
}
};
struct minus_func
{
template<class Sig> struct result;
template<class This,class A, class B>
struct result<This(A,B)>
{
typedef /*whatever*/ type;
};
template<class A, class B>
typename result<minus_func(A const&,B const&)>::type
plus_func(A const& lhs, B const& rhs)
{
return lhs-rhs;
}
};
struct my_grammar;
struct plus_rule : proto::plus<my_grammar, my_grammar> {};
struct minus_rule : proto::minus<my_grammar, my_grammar> {};
struct my_grammar
: proto::or_<
proto::when<proto::terminal<proto::_>, proto::_value>
, proto::when<plus_rule, proto::external_transform >
, proto::when<minus_rule, proto::external_transform >
>
{};
struct my_external_transforms
: proto::external_transforms<
proto::when<plus_rule, apply_func<plus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)>
, proto::when<minus_rule, apply_func<minus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)>
>
{};
Тип, возвращаемый каждым PFO, должен быть вычислен или указан. Помните, что A, B могут быть квалифицированы как const/ref и могут нуждаться в удалении перед выполнением вычисления типа.
Sidenote: external_transform вообще не требуется для рекурсивных правил. Я предполагаю, что пункт 4 (вызываемый шаблон) был тем, что заставило его не работать.