This is already optimal:
 Comp(T&& t, U&& u) : t_m(std::move(t)) , u_m(std::move(u)) { } 
If T has a move constructor, this will be a step. If it is not, it will be a copy - but then there is no way to make a copy somewhere. And it is not copied, then the whole question is controversial.
Of course, this only works for rvalues, so you need something for lvalues. This, unfortunately, is a bit more complicated:
 template <class Tx, class Ux, class = std::enable_if_t<std::is_convertible<std::decay_t<Tx>*, T*>::value && std::is_convertible<std::decay_t<Ux>*, U*>::value>> Comp(Tx&& t, Ux&& u) : t_m(std::forward<Tx>(t)) , u_m(std::forward<Ux>(u)) { } 
Here we want to resolve the derivation of Tx such that it is either T , T& , or D , D& , where D comes from T std::decay returns a reference and is_convertible for pointers, if one is received.
Ok, can we do better? Not really. This will either make 1 move or 1 instance for each participant. But what if we want to build them? We must be able to:
 template <class... TArgs, class... UArgs, class = std::enable_if_t<std::is_constructible<T, TArgs...>::value && std::is_constructible<U, UArgs...>::value>> Comp(std::piecewise_construct_t pc, std::tuple<TArgs...> const& t, std::tuple<UArgs...> const& u) : Comp(t, u, std::index_sequence_for<TArgs...>{}, std::index_sequence_for<UArgs...>{}) { } private: template <class TTuple, class UTuple, size_t... Is, size_t... Js> Comp(TTuple const& t, UTuple const& u, std::index_sequence<Is...>, std::index_sequence<Js...> ) : t_m(std::get<Is>(t)...) , u_m(std::get<Js>(u)...) { } 
With this, we can potentially avoid any copy or even move by simply creating it in place. Whether it is profitable or not, depends on the use of Comp .