Можно ли определить тип поля класса, исходя из типа объекта, возвращаемого функцией используемой в этом классе?
Очень странная потребность, но я постараюсь объяснить чем она вызвана на примере кода ниже. Я использую библиотеку для работы с pg под названием ozo, она базируется на boost::asio. Для того чтоб выполнить запрос, в функтор нужно передать collback c двумя аргументами, первый - код ошибки, второй - коннекшен. Вот это место в представленном ниже коде
reqOp.reqOp(std::move(provider), std::move(query), t, out, [this, coro](ozo::error_code ec,
auto conn) mutable {
this->ec = ec;
this->conn = conn;
coro.resume();
});
Тип коннекшена определяется на этапе компиляции исходя из многих факторов, все из передаваемого провайдера(первый аргумент функтора). До алгоритма определения в исходниках я докопаться не смог. Я пытаюсь написать обертку, позволяющую использовать эту библиотеку с корутинами с++20. Для этого я создаю класс Awaiter, в полях которого я хочу сохранять переданные в callback ошибку и конекшен. Проблема состоит в определении типа поля коннекшена в классе Awaiter. В примере ниже я использую тип
using ConnectionPtr = std::shared_ptr<ozo::pooled_connection<
yamail::resource_pool::handle<ozo::connection_rep<ozo::oid_map_t<>,
ozo::none_t>>, boost::asio::io_context::executor_type>>;\
Что неправильно, потому что данные тип подходит только для одного конкретного случая. Каким образом, исходя из типа, определяемого на этапе компиляции для второго аргумента колбека (ozo::error_code ec,auto conn) можно определить тип поля коннекшена в классе Awaiter. И возможно ли это сделать вообще. Необходимость сохранять конекшен в классе Awaiter возникла потому, что другого способа вернуть его через resume корутины, как известно мне, не предполагают. Как можно решить данную пробелму?
using ConnectionPtr = std::shared_ptr<ozo::pooled_connection<
yamail::resource_pool::handle<ozo::connection_rep<ozo::oid_map_t<>,
ozo::none_t>>, boost::asio::io_context::executor_type>>;
template<typename Initiator>
class RequestOp {
private:
ozo::request_op<Initiator> reqOp;
private:
template<typename P, typename Q, typename TimeConstraint, typename Out>
struct Awaiter {
const RequestOp<Initiator> &reqOp;
P &&provider;
Q &&query;
TimeConstraint t;
Out out;
ozo::error_code ec;
ConnectionPtr conn;
bool await_ready() {
return false;
}
void await_suspend(std::coroutine_handle<> coro) {
reqOp.reqOp(std::move(provider), std::move(query), t, out, [this, coro](ozo::error_code ec,
auto conn) mutable {
this->ec = ec;
this->conn = conn;
coro.resume();
});
}
decltype(auto) await_resume() {
return std::pair<ConnectionPtr, ozo::error_code>{conn, ec};
}
};
public:
template<typename P, typename Q, typename TimeConstraint, typename Out>
decltype(auto) operator()(P &&provider, Q &&query, TimeConstraint t, Out out) const {
return Awaiter<P, Q, TimeConstraint, Out>{*this, std::forward<P>(provider), std::forward<Q>(query), t, out};
}
};
constexpr RequestOp<ozo::detail::initiate_async_request> Request;