A pretty simple way to solve the issue would be providing a default argument for the comparator:
template <typename T, typename C = std::less<T>>
class multisets_merge_view { /* ... */ };
Since C++17 you can rely on class template argument deduction, which can simplify usage of your template class pretty much – you don't even have to provide a deduction guide for:
template <typename T, typename C>
class multisets_merge_view
{
public:
multisets_merge_view (std::multiset<T, C>& x, std::multiset<T, C>& y);
};
// the deduction guide (but not necessary)
template <typename T, typename C>
multisets_merge_view(std::multiset<T, C>& x, std::multiset<T, C>& y)
-> multisets_merge_view <T, C>;
This allows using your class like:
multisets_merge_view mvi(a, b);
multisets_merge_view mvi_g(ga, gb);
Note: There's no need to specify any template arguments at all any more...
Yet another variant is having your view class totally generic:
template <typename T>
class generic_merge_view
{
using Compare = typename T::key_compare;
public:
generic_merge_view(T& x, T& y)
{
// just for demonstration
Compare c;
for(auto ix = x.begin(), iy = y.begin(); /*...*/; ++ix, ++iy)
{
if(c(*ix, *iy))
{
// do something
}
}
}
};
You profit from duck-typing: As long as a type provides all the features the template requires – in this case the key_compare typedef and the ability to iterate – you can use it, this would comprise e.g. std::set, std::map and std::multimap as well.
The template type then differs, though (it's the set or map itself, not just the set/map's template arguments), but with CTAD you don't need to care for...