connect.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. //
  2. // impl/connect.hpp
  3. // ~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_IMPL_CONNECT_HPP
  11. #define BOOST_ASIO_IMPL_CONNECT_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <algorithm>
  16. #include <boost/asio/associator.hpp>
  17. #include <boost/asio/detail/base_from_cancellation_state.hpp>
  18. #include <boost/asio/detail/bind_handler.hpp>
  19. #include <boost/asio/detail/handler_cont_helpers.hpp>
  20. #include <boost/asio/detail/handler_tracking.hpp>
  21. #include <boost/asio/detail/handler_type_requirements.hpp>
  22. #include <boost/asio/detail/non_const_lvalue.hpp>
  23. #include <boost/asio/detail/throw_error.hpp>
  24. #include <boost/asio/detail/type_traits.hpp>
  25. #include <boost/asio/error.hpp>
  26. #include <boost/asio/post.hpp>
  27. #include <boost/asio/detail/push_options.hpp>
  28. namespace boost {
  29. namespace asio {
  30. namespace detail
  31. {
  32. template <typename Protocol, typename Iterator>
  33. inline typename Protocol::endpoint deref_connect_result(
  34. Iterator iter, boost::system::error_code& ec)
  35. {
  36. return ec ? typename Protocol::endpoint() : *iter;
  37. }
  38. template <typename ConnectCondition, typename Iterator>
  39. inline Iterator call_connect_condition(ConnectCondition& connect_condition,
  40. const boost::system::error_code& ec, Iterator next, Iterator end,
  41. constraint_t<
  42. is_same<
  43. result_of_t<ConnectCondition(boost::system::error_code, Iterator)>,
  44. Iterator
  45. >::value
  46. > = 0)
  47. {
  48. if (next != end)
  49. return connect_condition(ec, next);
  50. return end;
  51. }
  52. template <typename ConnectCondition, typename Iterator>
  53. inline Iterator call_connect_condition(ConnectCondition& connect_condition,
  54. const boost::system::error_code& ec, Iterator next, Iterator end,
  55. constraint_t<
  56. is_same<
  57. result_of_t<ConnectCondition(boost::system::error_code,
  58. decltype(*declval<Iterator>()))>,
  59. bool
  60. >::value
  61. > = 0)
  62. {
  63. for (;next != end; ++next)
  64. if (connect_condition(ec, *next))
  65. return next;
  66. return end;
  67. }
  68. } // namespace detail
  69. template <typename Protocol, typename Executor, typename EndpointSequence>
  70. typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
  71. const EndpointSequence& endpoints,
  72. constraint_t<
  73. is_endpoint_sequence<EndpointSequence>::value
  74. >)
  75. {
  76. boost::system::error_code ec;
  77. typename Protocol::endpoint result = connect(s, endpoints, ec);
  78. boost::asio::detail::throw_error(ec, "connect");
  79. return result;
  80. }
  81. template <typename Protocol, typename Executor, typename EndpointSequence>
  82. typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
  83. const EndpointSequence& endpoints, boost::system::error_code& ec,
  84. constraint_t<
  85. is_endpoint_sequence<EndpointSequence>::value
  86. >)
  87. {
  88. return detail::deref_connect_result<Protocol>(
  89. connect(s, endpoints.begin(), endpoints.end(),
  90. detail::default_connect_condition(), ec), ec);
  91. }
  92. #if !defined(BOOST_ASIO_NO_DEPRECATED)
  93. template <typename Protocol, typename Executor, typename Iterator>
  94. Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
  95. constraint_t<
  96. !is_endpoint_sequence<Iterator>::value
  97. >)
  98. {
  99. boost::system::error_code ec;
  100. Iterator result = connect(s, begin, ec);
  101. boost::asio::detail::throw_error(ec, "connect");
  102. return result;
  103. }
  104. template <typename Protocol, typename Executor, typename Iterator>
  105. inline Iterator connect(basic_socket<Protocol, Executor>& s,
  106. Iterator begin, boost::system::error_code& ec,
  107. constraint_t<
  108. !is_endpoint_sequence<Iterator>::value
  109. >)
  110. {
  111. return connect(s, begin, Iterator(), detail::default_connect_condition(), ec);
  112. }
  113. #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
  114. template <typename Protocol, typename Executor, typename Iterator>
  115. Iterator connect(basic_socket<Protocol, Executor>& s,
  116. Iterator begin, Iterator end)
  117. {
  118. boost::system::error_code ec;
  119. Iterator result = connect(s, begin, end, ec);
  120. boost::asio::detail::throw_error(ec, "connect");
  121. return result;
  122. }
  123. template <typename Protocol, typename Executor, typename Iterator>
  124. inline Iterator connect(basic_socket<Protocol, Executor>& s,
  125. Iterator begin, Iterator end, boost::system::error_code& ec)
  126. {
  127. return connect(s, begin, end, detail::default_connect_condition(), ec);
  128. }
  129. template <typename Protocol, typename Executor,
  130. typename EndpointSequence, typename ConnectCondition>
  131. typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
  132. const EndpointSequence& endpoints, ConnectCondition connect_condition,
  133. constraint_t<
  134. is_endpoint_sequence<EndpointSequence>::value
  135. >,
  136. constraint_t<
  137. is_connect_condition<ConnectCondition,
  138. decltype(declval<const EndpointSequence&>().begin())>::value
  139. >)
  140. {
  141. boost::system::error_code ec;
  142. typename Protocol::endpoint result = connect(
  143. s, endpoints, connect_condition, ec);
  144. boost::asio::detail::throw_error(ec, "connect");
  145. return result;
  146. }
  147. template <typename Protocol, typename Executor,
  148. typename EndpointSequence, typename ConnectCondition>
  149. typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
  150. const EndpointSequence& endpoints, ConnectCondition connect_condition,
  151. boost::system::error_code& ec,
  152. constraint_t<
  153. is_endpoint_sequence<EndpointSequence>::value
  154. >,
  155. constraint_t<
  156. is_connect_condition<ConnectCondition,
  157. decltype(declval<const EndpointSequence&>().begin())>::value
  158. >)
  159. {
  160. return detail::deref_connect_result<Protocol>(
  161. connect(s, endpoints.begin(), endpoints.end(),
  162. connect_condition, ec), ec);
  163. }
  164. #if !defined(BOOST_ASIO_NO_DEPRECATED)
  165. template <typename Protocol, typename Executor,
  166. typename Iterator, typename ConnectCondition>
  167. Iterator connect(basic_socket<Protocol, Executor>& s,
  168. Iterator begin, ConnectCondition connect_condition,
  169. constraint_t<
  170. !is_endpoint_sequence<Iterator>::value
  171. >,
  172. constraint_t<
  173. is_connect_condition<ConnectCondition, Iterator>::value
  174. >)
  175. {
  176. boost::system::error_code ec;
  177. Iterator result = connect(s, begin, connect_condition, ec);
  178. boost::asio::detail::throw_error(ec, "connect");
  179. return result;
  180. }
  181. template <typename Protocol, typename Executor,
  182. typename Iterator, typename ConnectCondition>
  183. inline Iterator connect(basic_socket<Protocol, Executor>& s,
  184. Iterator begin, ConnectCondition connect_condition,
  185. boost::system::error_code& ec,
  186. constraint_t<
  187. !is_endpoint_sequence<Iterator>::value
  188. >,
  189. constraint_t<
  190. is_connect_condition<ConnectCondition, Iterator>::value
  191. >)
  192. {
  193. return connect(s, begin, Iterator(), connect_condition, ec);
  194. }
  195. #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
  196. template <typename Protocol, typename Executor,
  197. typename Iterator, typename ConnectCondition>
  198. Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
  199. Iterator end, ConnectCondition connect_condition,
  200. constraint_t<
  201. is_connect_condition<ConnectCondition, Iterator>::value
  202. >)
  203. {
  204. boost::system::error_code ec;
  205. Iterator result = connect(s, begin, end, connect_condition, ec);
  206. boost::asio::detail::throw_error(ec, "connect");
  207. return result;
  208. }
  209. template <typename Protocol, typename Executor,
  210. typename Iterator, typename ConnectCondition>
  211. Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
  212. Iterator end, ConnectCondition connect_condition,
  213. boost::system::error_code& ec,
  214. constraint_t<
  215. is_connect_condition<ConnectCondition, Iterator>::value
  216. >)
  217. {
  218. ec = boost::system::error_code();
  219. for (Iterator iter = begin; iter != end; ++iter)
  220. {
  221. iter = (detail::call_connect_condition(connect_condition, ec, iter, end));
  222. if (iter != end)
  223. {
  224. s.close(ec);
  225. s.connect(*iter, ec);
  226. if (!ec)
  227. return iter;
  228. }
  229. else
  230. break;
  231. }
  232. if (!ec)
  233. ec = boost::asio::error::not_found;
  234. return end;
  235. }
  236. namespace detail
  237. {
  238. // Enable the empty base class optimisation for the connect condition.
  239. template <typename ConnectCondition>
  240. class base_from_connect_condition
  241. {
  242. protected:
  243. explicit base_from_connect_condition(
  244. const ConnectCondition& connect_condition)
  245. : connect_condition_(connect_condition)
  246. {
  247. }
  248. template <typename Iterator>
  249. void check_condition(const boost::system::error_code& ec,
  250. Iterator& iter, Iterator& end)
  251. {
  252. iter = detail::call_connect_condition(connect_condition_, ec, iter, end);
  253. }
  254. private:
  255. ConnectCondition connect_condition_;
  256. };
  257. // The default_connect_condition implementation is essentially a no-op. This
  258. // template specialisation lets us eliminate all costs associated with it.
  259. template <>
  260. class base_from_connect_condition<default_connect_condition>
  261. {
  262. protected:
  263. explicit base_from_connect_condition(const default_connect_condition&)
  264. {
  265. }
  266. template <typename Iterator>
  267. void check_condition(const boost::system::error_code&, Iterator&, Iterator&)
  268. {
  269. }
  270. };
  271. template <typename Protocol, typename Executor, typename EndpointSequence,
  272. typename ConnectCondition, typename RangeConnectHandler>
  273. class range_connect_op
  274. : public base_from_cancellation_state<RangeConnectHandler>,
  275. base_from_connect_condition<ConnectCondition>
  276. {
  277. public:
  278. range_connect_op(basic_socket<Protocol, Executor>& sock,
  279. const EndpointSequence& endpoints,
  280. const ConnectCondition& connect_condition,
  281. RangeConnectHandler& handler)
  282. : base_from_cancellation_state<RangeConnectHandler>(
  283. handler, enable_partial_cancellation()),
  284. base_from_connect_condition<ConnectCondition>(connect_condition),
  285. socket_(sock),
  286. endpoints_(endpoints),
  287. index_(0),
  288. start_(0),
  289. handler_(static_cast<RangeConnectHandler&&>(handler))
  290. {
  291. }
  292. range_connect_op(const range_connect_op& other)
  293. : base_from_cancellation_state<RangeConnectHandler>(other),
  294. base_from_connect_condition<ConnectCondition>(other),
  295. socket_(other.socket_),
  296. endpoints_(other.endpoints_),
  297. index_(other.index_),
  298. start_(other.start_),
  299. handler_(other.handler_)
  300. {
  301. }
  302. range_connect_op(range_connect_op&& other)
  303. : base_from_cancellation_state<RangeConnectHandler>(
  304. static_cast<base_from_cancellation_state<RangeConnectHandler>&&>(
  305. other)),
  306. base_from_connect_condition<ConnectCondition>(other),
  307. socket_(other.socket_),
  308. endpoints_(other.endpoints_),
  309. index_(other.index_),
  310. start_(other.start_),
  311. handler_(static_cast<RangeConnectHandler&&>(other.handler_))
  312. {
  313. }
  314. void operator()(boost::system::error_code ec, int start = 0)
  315. {
  316. this->process(ec, start,
  317. const_cast<const EndpointSequence&>(endpoints_).begin(),
  318. const_cast<const EndpointSequence&>(endpoints_).end());
  319. }
  320. //private:
  321. template <typename Iterator>
  322. void process(boost::system::error_code ec,
  323. int start, Iterator begin, Iterator end)
  324. {
  325. Iterator iter = begin;
  326. std::advance(iter, index_);
  327. switch (start_ = start)
  328. {
  329. case 1:
  330. for (;;)
  331. {
  332. this->check_condition(ec, iter, end);
  333. index_ = std::distance(begin, iter);
  334. if (iter != end)
  335. {
  336. socket_.close(ec);
  337. BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
  338. socket_.async_connect(*iter,
  339. static_cast<range_connect_op&&>(*this));
  340. return;
  341. }
  342. if (start)
  343. {
  344. ec = boost::asio::error::not_found;
  345. BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
  346. boost::asio::post(socket_.get_executor(),
  347. detail::bind_handler(
  348. static_cast<range_connect_op&&>(*this), ec));
  349. return;
  350. }
  351. /* fall-through */ default:
  352. if (iter == end)
  353. break;
  354. if (!socket_.is_open())
  355. {
  356. ec = boost::asio::error::operation_aborted;
  357. break;
  358. }
  359. if (!ec)
  360. break;
  361. if (this->cancelled() != cancellation_type::none)
  362. {
  363. ec = boost::asio::error::operation_aborted;
  364. break;
  365. }
  366. ++iter;
  367. ++index_;
  368. }
  369. static_cast<RangeConnectHandler&&>(handler_)(
  370. static_cast<const boost::system::error_code&>(ec),
  371. static_cast<const typename Protocol::endpoint&>(
  372. ec || iter == end ? typename Protocol::endpoint() : *iter));
  373. }
  374. }
  375. basic_socket<Protocol, Executor>& socket_;
  376. EndpointSequence endpoints_;
  377. std::size_t index_;
  378. int start_;
  379. RangeConnectHandler handler_;
  380. };
  381. template <typename Protocol, typename Executor, typename EndpointSequence,
  382. typename ConnectCondition, typename RangeConnectHandler>
  383. inline bool asio_handler_is_continuation(
  384. range_connect_op<Protocol, Executor, EndpointSequence,
  385. ConnectCondition, RangeConnectHandler>* this_handler)
  386. {
  387. return boost_asio_handler_cont_helpers::is_continuation(
  388. this_handler->handler_);
  389. }
  390. template <typename Protocol, typename Executor>
  391. class initiate_async_range_connect
  392. {
  393. public:
  394. typedef Executor executor_type;
  395. explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s)
  396. : socket_(s)
  397. {
  398. }
  399. executor_type get_executor() const noexcept
  400. {
  401. return socket_.get_executor();
  402. }
  403. template <typename RangeConnectHandler,
  404. typename EndpointSequence, typename ConnectCondition>
  405. void operator()(RangeConnectHandler&& handler,
  406. const EndpointSequence& endpoints,
  407. const ConnectCondition& connect_condition) const
  408. {
  409. // If you get an error on the following line it means that your
  410. // handler does not meet the documented type requirements for an
  411. // RangeConnectHandler.
  412. BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler,
  413. handler, typename Protocol::endpoint) type_check;
  414. non_const_lvalue<RangeConnectHandler> handler2(handler);
  415. range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition,
  416. decay_t<RangeConnectHandler>>(socket_, endpoints,
  417. connect_condition, handler2.value)(boost::system::error_code(), 1);
  418. }
  419. private:
  420. basic_socket<Protocol, Executor>& socket_;
  421. };
  422. template <typename Protocol, typename Executor, typename Iterator,
  423. typename ConnectCondition, typename IteratorConnectHandler>
  424. class iterator_connect_op
  425. : public base_from_cancellation_state<IteratorConnectHandler>,
  426. base_from_connect_condition<ConnectCondition>
  427. {
  428. public:
  429. iterator_connect_op(basic_socket<Protocol, Executor>& sock,
  430. const Iterator& begin, const Iterator& end,
  431. const ConnectCondition& connect_condition,
  432. IteratorConnectHandler& handler)
  433. : base_from_cancellation_state<IteratorConnectHandler>(
  434. handler, enable_partial_cancellation()),
  435. base_from_connect_condition<ConnectCondition>(connect_condition),
  436. socket_(sock),
  437. iter_(begin),
  438. end_(end),
  439. start_(0),
  440. handler_(static_cast<IteratorConnectHandler&&>(handler))
  441. {
  442. }
  443. iterator_connect_op(const iterator_connect_op& other)
  444. : base_from_cancellation_state<IteratorConnectHandler>(other),
  445. base_from_connect_condition<ConnectCondition>(other),
  446. socket_(other.socket_),
  447. iter_(other.iter_),
  448. end_(other.end_),
  449. start_(other.start_),
  450. handler_(other.handler_)
  451. {
  452. }
  453. iterator_connect_op(iterator_connect_op&& other)
  454. : base_from_cancellation_state<IteratorConnectHandler>(
  455. static_cast<base_from_cancellation_state<IteratorConnectHandler>&&>(
  456. other)),
  457. base_from_connect_condition<ConnectCondition>(other),
  458. socket_(other.socket_),
  459. iter_(other.iter_),
  460. end_(other.end_),
  461. start_(other.start_),
  462. handler_(static_cast<IteratorConnectHandler&&>(other.handler_))
  463. {
  464. }
  465. void operator()(boost::system::error_code ec, int start = 0)
  466. {
  467. switch (start_ = start)
  468. {
  469. case 1:
  470. for (;;)
  471. {
  472. this->check_condition(ec, iter_, end_);
  473. if (iter_ != end_)
  474. {
  475. socket_.close(ec);
  476. BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
  477. socket_.async_connect(*iter_,
  478. static_cast<iterator_connect_op&&>(*this));
  479. return;
  480. }
  481. if (start)
  482. {
  483. ec = boost::asio::error::not_found;
  484. BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
  485. boost::asio::post(socket_.get_executor(),
  486. detail::bind_handler(
  487. static_cast<iterator_connect_op&&>(*this), ec));
  488. return;
  489. }
  490. /* fall-through */ default:
  491. if (iter_ == end_)
  492. break;
  493. if (!socket_.is_open())
  494. {
  495. ec = boost::asio::error::operation_aborted;
  496. break;
  497. }
  498. if (!ec)
  499. break;
  500. if (this->cancelled() != cancellation_type::none)
  501. {
  502. ec = boost::asio::error::operation_aborted;
  503. break;
  504. }
  505. ++iter_;
  506. }
  507. static_cast<IteratorConnectHandler&&>(handler_)(
  508. static_cast<const boost::system::error_code&>(ec),
  509. static_cast<const Iterator&>(iter_));
  510. }
  511. }
  512. //private:
  513. basic_socket<Protocol, Executor>& socket_;
  514. Iterator iter_;
  515. Iterator end_;
  516. int start_;
  517. IteratorConnectHandler handler_;
  518. };
  519. template <typename Protocol, typename Executor, typename Iterator,
  520. typename ConnectCondition, typename IteratorConnectHandler>
  521. inline bool asio_handler_is_continuation(
  522. iterator_connect_op<Protocol, Executor, Iterator,
  523. ConnectCondition, IteratorConnectHandler>* this_handler)
  524. {
  525. return boost_asio_handler_cont_helpers::is_continuation(
  526. this_handler->handler_);
  527. }
  528. template <typename Protocol, typename Executor>
  529. class initiate_async_iterator_connect
  530. {
  531. public:
  532. typedef Executor executor_type;
  533. explicit initiate_async_iterator_connect(
  534. basic_socket<Protocol, Executor>& s)
  535. : socket_(s)
  536. {
  537. }
  538. executor_type get_executor() const noexcept
  539. {
  540. return socket_.get_executor();
  541. }
  542. template <typename IteratorConnectHandler,
  543. typename Iterator, typename ConnectCondition>
  544. void operator()(IteratorConnectHandler&& handler,
  545. Iterator begin, Iterator end,
  546. const ConnectCondition& connect_condition) const
  547. {
  548. // If you get an error on the following line it means that your
  549. // handler does not meet the documented type requirements for an
  550. // IteratorConnectHandler.
  551. BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK(
  552. IteratorConnectHandler, handler, Iterator) type_check;
  553. non_const_lvalue<IteratorConnectHandler> handler2(handler);
  554. iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition,
  555. decay_t<IteratorConnectHandler>>(socket_, begin, end,
  556. connect_condition, handler2.value)(boost::system::error_code(), 1);
  557. }
  558. private:
  559. basic_socket<Protocol, Executor>& socket_;
  560. };
  561. } // namespace detail
  562. #if !defined(GENERATING_DOCUMENTATION)
  563. template <template <typename, typename> class Associator,
  564. typename Protocol, typename Executor, typename EndpointSequence,
  565. typename ConnectCondition, typename RangeConnectHandler,
  566. typename DefaultCandidate>
  567. struct associator<Associator,
  568. detail::range_connect_op<Protocol, Executor,
  569. EndpointSequence, ConnectCondition, RangeConnectHandler>,
  570. DefaultCandidate>
  571. : Associator<RangeConnectHandler, DefaultCandidate>
  572. {
  573. static typename Associator<RangeConnectHandler, DefaultCandidate>::type get(
  574. const detail::range_connect_op<Protocol, Executor, EndpointSequence,
  575. ConnectCondition, RangeConnectHandler>& h) noexcept
  576. {
  577. return Associator<RangeConnectHandler, DefaultCandidate>::get(h.handler_);
  578. }
  579. static auto get(
  580. const detail::range_connect_op<Protocol, Executor,
  581. EndpointSequence, ConnectCondition, RangeConnectHandler>& h,
  582. const DefaultCandidate& c) noexcept
  583. -> decltype(
  584. Associator<RangeConnectHandler, DefaultCandidate>::get(
  585. h.handler_, c))
  586. {
  587. return Associator<RangeConnectHandler, DefaultCandidate>::get(
  588. h.handler_, c);
  589. }
  590. };
  591. template <template <typename, typename> class Associator,
  592. typename Protocol, typename Executor, typename Iterator,
  593. typename ConnectCondition, typename IteratorConnectHandler,
  594. typename DefaultCandidate>
  595. struct associator<Associator,
  596. detail::iterator_connect_op<Protocol, Executor,
  597. Iterator, ConnectCondition, IteratorConnectHandler>,
  598. DefaultCandidate>
  599. : Associator<IteratorConnectHandler, DefaultCandidate>
  600. {
  601. static typename Associator<IteratorConnectHandler, DefaultCandidate>::type
  602. get(const detail::iterator_connect_op<Protocol, Executor, Iterator,
  603. ConnectCondition, IteratorConnectHandler>& h) noexcept
  604. {
  605. return Associator<IteratorConnectHandler, DefaultCandidate>::get(
  606. h.handler_);
  607. }
  608. static auto get(
  609. const detail::iterator_connect_op<Protocol, Executor,
  610. Iterator, ConnectCondition, IteratorConnectHandler>& h,
  611. const DefaultCandidate& c) noexcept
  612. -> decltype(
  613. Associator<IteratorConnectHandler, DefaultCandidate>::get(
  614. h.handler_, c))
  615. {
  616. return Associator<IteratorConnectHandler, DefaultCandidate>::get(
  617. h.handler_, c);
  618. }
  619. };
  620. #endif // !defined(GENERATING_DOCUMENTATION)
  621. } // namespace asio
  622. } // namespace boost
  623. #include <boost/asio/detail/pop_options.hpp>
  624. #endif // BOOST_ASIO_IMPL_CONNECT_HPP