How to limit parameter type to allow only std :: initializer_list <size_t> or std :: array <size_t, N>?

I would like to have only one template function. So I figured out how ...

template<typename Iteratable, size_t N, typename = std::enable_if_t< std::is_same_v<Iteratable, const std::initializer_list<size_t> > || std::is_same_v<Iteratable, const std::array<size_t, N > > > > std::ostream& operator << (std::ostream& os, Iteratable& in) { std::copy(std::begin(in), std::end(in), std::ostream_iterator<size_t>(os, " ") ); return os; } 

It seems that due to N in std::array<size_t, N> specialization fails.

Is there a way to not write function 2 for this use case?

+5
source share
1 answer

If the only reason you don’t want to overload is to avoid duplicating the function body, you can use your own trait instead for writing. One such way:

 namespace details { template<class Iterable> struct writable : std::false_type {}; template<size_t N> struct writable<std::array<std::size_t, N>> : std::true_type {}; template<> struct writable<std::initializer_list<size_t>> : std::true_type {}; template<class Iterable> constexpr bool writable_v = writable<Iterable>::value; } template<typename Iteratable, std::enable_if_t<details::writable_v<std::decay_t<Iteratable>>, int> = 0 > std::ostream& operator << (std::ostream& os, Iteratable& in) { std::copy(std::begin(in), std::end(in), std::ostream_iterator<size_t>(os, " ") ); return os; } 

I also took the liberty of moving enable_if into the template argument. Thus, SFINAE cannot be bypassed by specifying a type name for both arguments (although admittedly this is unlikely to happen for an overloaded operator).

Another nice fact is that the tuning point is now separate from the function definition itself. Adding new iterations is simply a matter of adding another specialization for details::writable .

Live example

+8
source

Source: https://habr.com/ru/post/1274439/


All Articles