Переписать: я пропустил пункт в моем первом ответе (было поздно), позвольте мне повторить попытку.
Позвольте мне рассказать о таких людях, как я, которые могут упустить вашу мысль в первый раз. В boost :: lambda при использовании пользовательских типов в выражениях операторов необходимо использовать функцию ret <> для отмены вывода возвращаемого типа. Это потому, что система вывода лямбда-возвращаемых типов напрямую поддерживает только нативные (и stl? Я не помню) типы. Краткий пример:
using namespace boost::lambda;
struct add_t{
add_t(int i) : i(i) {};
add_t operator+(const add_t& other) const{
return add_t(i + other.i);
}
int i;
};
(_1 + _2)(add_t(38), add_t(4)); // RETURN TYPE DEDUCTION FAILS
ret<add_t>(_1 + _2)(add_t(38), add_t(4)); // OK
Однако в Phoenix подсказки не нужны (обратите внимание, что литералы и неконстантные временные символы не могут появиться в списке аргументов Phoenix):
using namespace boost::phoenix;
add_t i(38), j(4);
(_1 + _2)(i, j); // JUST FINE
Система дедукции обратного типа совершенно другая и гораздо более естественная в Фениксе; он будет правильно выводить тип возвращаемых операторов, которые используют обычную семантику. В частности, возвращаемый тип должен соответствовать типу одного из операндов, быть ссылкой, указателем или константным указателем на один из типов аргументов или быть итератором контейнера / контейнера stl одного из этих типов. В заголовке type_deduction.hpp есть хорошая запись вывода типа Phoenix для получения более подробной информации.
Итак, сейчас я читаю ваш вопрос: как можно обрабатывать нетрадиционную семантику операторов в Фениксе?
Рассмотрим следующую странную пару типов в качестве примера
struct add_ret_t{
add_ret_t(int i) : i(i) {};
int i;
};
struct add_t{
add_t(int i) : i(i) {};
add_ret_t operator+(const add_t& other) const{
return add_ret_t(i + other.i);
}
int i;
};
Для лямбды это не проблема, просто используйте функцию ret:
using namespace boost::lambda;
ret<add_ret_t>(_1 + _2)(add_t(38), add_t(4)); // OK
Но Феникс не может справиться с этим оператором (вы можете винить его?), Потому что тип возвращаемого значения не связан с аргументами, и нет способа напрямую указать тип возвращаемого значения в Фениксе. Если есть веская причина для использования такого оператора, такой случай можно добавить в систему дедукции типов, но я не могу найти способ сделать это без взлома type_deduction.hpp или ветвления хорошей части Феникса.
В качестве альтернативы, я решил немного взломать, чтобы переопределить типы возвращаемых данных для определенных операторов. Result_of_ операция шаблонные структуры в boost / spirit / home / phoenix / operator / arithmetic.hpp (строки 39-56 перечисляют типы структур, boost 1.43) выполняют вывод типов при их создании и сохраняют результат , Таким образом, все, что нужно, это предоставить некоторые шаблонные специализации для проблемных операций, которые должны содержать только один typedef, указывающий тип возвращаемого значения. Пример ( кодовая панель для полной версии ):
using namespace boost::phoenix;
namespace boost{ namespace phoenix{
//override add_t addition to give add_ret_t
template <> struct result_of_plus<add_t&, add_t&> { typedef add_ret_t type; };
//override int addition to give char
template <> struct result_of_plus<int&, int&> { typedef char type; };
}}
int main()
{
add_t i = 1, j = 7;
std::cout << ((_1 + _2)(i, j)).i << std::endl;
int k = 51, l = 37;
std::cout << ((_1 + _2)(k, l)) << std::endl;
return 0;
}
Это, конечно, не замена, но в некоторых отношениях она лучше, чем глобальная. Если существует много операторов для перегрузки, весь набор операций может быть макросирован.