Skip to content

Commit dbf4504

Browse files
committed
router converting constructors
1 parent b5baf80 commit dbf4504

2 files changed

Lines changed: 93 additions & 9 deletions

File tree

include/boost/http/server/router.hpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ struct identity
391391
template<class P = route_params, class HT = identity>
392392
class router : public detail::router_base
393393
{
394+
template<class, class> friend class router;
395+
394396
HT ht_{};
395397

396398
static_assert(std::derived_from<P, route_params>);
@@ -601,25 +603,43 @@ class router : public detail::router_base
601603
/** Construct a router from another router with compatible types.
602604
603605
This constructs a router that shares the same underlying routing
604-
state as another router whose params type is a base class of `Params`.
606+
state as another router whose params and handler transform types
607+
may differ.
605608
606-
The resulting router participates in shared ownership of the
607-
implementation; copying the router does not duplicate routes or
608-
handlers, and changes visible through one router are visible
609-
through all routers that share the same underlying state.
609+
The handler transform is initialized as follows:
610+
- If `HT` is constructible from `OtherHT`, the transform is
611+
move-constructed from the source router's transform.
612+
- Otherwise, if `HT` is default-constructible, the transform
613+
is value-initialized.
610614
611615
@par Constraints
612616
613-
`Params` must be derived from `OtherParams`.
617+
`OtherParams` must be derived from `Params`, and `HT` must be
618+
either constructible from `OtherHT` or default-constructible.
614619
615620
@param other The router to construct from.
616621
617622
@tparam OtherParams The params type of the source router.
623+
624+
@tparam OtherHT The handler transform type of the source router.
618625
*/
619-
template<class OtherP>
620-
requires std::derived_from<OtherP, P>
626+
template<class OtherP, class OtherHT>
627+
requires std::derived_from<OtherP, P> &&
628+
std::constructible_from<HT, OtherHT>
629+
router(
630+
router<OtherP, OtherHT>&& other) noexcept
631+
: detail::router_base(std::move(other))
632+
, ht_(std::move(other.ht_))
633+
{
634+
}
635+
636+
/// @copydoc router(router<OtherP,OtherHT>&&)
637+
template<class OtherP, class OtherHT>
638+
requires std::derived_from<OtherP, P> &&
639+
(!std::constructible_from<HT, OtherHT>) &&
640+
std::default_initializable<HT>
621641
router(
622-
router<OtherP>&& other) noexcept
642+
router<OtherP, OtherHT>&& other) noexcept
623643
: detail::router_base(std::move(other))
624644
{
625645
}

test/unit/server/router.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ struct router_test
2121
using params = route_params;
2222
using test_router = router<params>;
2323

24+
struct derived_params : params {};
25+
26+
struct my_transform
27+
{
28+
template<class T>
29+
T operator()(T&& t) const
30+
{ return std::forward<T>(t); }
31+
};
32+
33+
struct base_ht
34+
{
35+
template<class T>
36+
T operator()(T&& t) const
37+
{ return std::forward<T>(t); }
38+
};
39+
40+
struct derived_ht : base_ht {};
41+
2442
//--------------------------------------------
2543
// Simple handlers - no destructor verification
2644
//--------------------------------------------
@@ -435,6 +453,51 @@ struct router_test
435453
{ test_router r; r.add(GET, "/auth/login", h_next); check(r, GET, "/auth%2flogin", route_next); }
436454
}
437455

456+
void testCrossTypeConstruction()
457+
{
458+
// HT constructible from OtherHT (identity -> identity)
459+
{
460+
router<params> r1;
461+
r1.use(h_send);
462+
router<params> r2(std::move(r1));
463+
check(r2, "/");
464+
}
465+
466+
// different P, same default HT
467+
{
468+
router<derived_params> r1;
469+
r1.use([](derived_params&) -> route_task
470+
{ co_return route_result{}; });
471+
router<params> r2(std::move(r1));
472+
(void)r2;
473+
}
474+
475+
// HT not constructible from OtherHT, but default constructible
476+
{
477+
router<params> r1;
478+
r1.use(h_send);
479+
router<params, my_transform> r2(std::move(r1));
480+
(void)r2;
481+
}
482+
483+
// HT constructible from OtherHT (derived -> base)
484+
{
485+
router<params, derived_ht> r1;
486+
r1.use(h_send);
487+
router<params, base_ht> r2(std::move(r1));
488+
(void)r2;
489+
}
490+
491+
// both P and HT differ
492+
{
493+
router<derived_params> r1;
494+
r1.use([](derived_params&) -> route_task
495+
{ co_return route_result{}; });
496+
router<params, my_transform> r2(std::move(r1));
497+
(void)r2;
498+
}
499+
}
500+
438501
void run()
439502
{
440503
testUse();
@@ -445,6 +508,7 @@ struct router_test
445508
testOptions();
446509
testDispatch();
447510
testPathDecoding();
511+
testCrossTypeConstruction();
448512
}
449513
};
450514

0 commit comments

Comments
 (0)