Я хотел бы построить на примере Boost Proto «Распаковка выражений» из Вот с помощью параметра шаблона, чтобы указать тип возвращаемого значения do_eval
преобразовать (доселе double
).
Для краткости я представлю рабочую, упрощенную (плюс-только) версию do_eval
:
struct do_eval2 : proto::callable
{
typedef double result_type;
template <typename X, typename Y>
result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};
Затем я добавляю параметр шаблона T
вместо double
:
template <typename T>
struct do_eval2 : proto::callable
{
typedef T result_type;
template <typename X, typename Y>
result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};
и изменить связанный eval
структура для:
struct eval2
: proto::or_<
proto::when<proto::terminal<proto::_>, proto::_value>
, proto::otherwise<do_eval2<double>(proto::tag_of<proto::_>(),
eval2(proto::pack(proto::_))...)>
>
{};
но когда я использую его, как показано в коде ниже, я получаю ошибки, начиная с ошибка: невозможно привязать значение ‘std :: ostream {aka std :: basic_ostream} к значению ‘std :: basic_ostream&&» Как я могу удовлетворить компилятор?
int main(int argc, char *argv[])
{
int one = 1, two = 2;
cout << eval2()(phoenix::ref(one)+phoenix::ref(two)) << '\n';
return 0;
}
Как вы видете Вот:
Преобразования обычно имеют форму proto :: when< Что-то, R (A0, A1, …)>. Вопрос в том, представляет ли R вызываемую функцию или объект для конструирования, и ответ определяет, как proto :: when<> оценивает преобразование. прото :: когда<> использует proto :: is_callable<> Черта для разногласий между двумя. Proto делает все возможное, чтобы угадать, является ли тип вызываемым или нет, но он не всегда понимает это правильно. Лучше знать правила, которые использует Proto, чтобы вы знали, когда вам нужно быть более явным.
Для большинства типов R proto :: is_callable проверяет наследование от proto :: callable. Однако, если тип R является специализацией шаблона, Proto предполагает, что он не может быть вызван, даже если шаблон наследуется от proto :: callable.
Документация предлагает решения: вы можете обернуть каждый вызов do_eval<double>
с proto::call
или ты просто специализируешься is_callable
внутри пространства имен boost :: proto и забудьте о проблеме.
namespace boost { namespace proto
{
// Tell Proto that do_eval2<> is callable
template<typename T>
struct is_callable<do_eval2<T> >
: mpl::true_
{};
}}
[Править:] Вот proto::call
альтернатива:
struct eval2
: proto::or_<
proto::when<proto::terminal<proto::_>, proto::_value>
, proto::otherwise<
proto::call<do_eval2<double>(proto::tag_of<proto::_>(),
eval2(proto::pack(proto::_))...)>>
>
{};
Смотрите предыдущий ответ. Я также добавил бы, что другое решение было бы определить do_eval2
как это:
template <typename T, typename D = proto::callable>
struct do_eval2 : proto::callable
{
typedef T result_type;
template <typename X, typename Y>
result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};
Обратите внимание на дополнительный фиктивный параметр шаблона.
РЕДАКТИРОВАТЬ: Кроме того, в следующей версии Proto, которая в настоящее время находится в стадии разработки, вам не нужно будет знать об этой части тайны, и все должно просто работать. Я буду говорить об этом на C ++ Теперь через несколько недель.