如何约束参数类型只允许std :: initializer_list <size_t>或std :: array <size_t,N>?

san*_*orn 5 c++ templates template-meta-programming

我想只有一个模板功能.所以我想出来......

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;
}
Run Code Online (Sandbox Code Playgroud)

似乎因为Nin std::array<size_t, N>,专业化失败了.

有没有怎么不写这个用例的2函数?

Sto*_*ica 8

如果你不想重载的唯一原因是为了避免重复功能体,你可以改为编写自己的特征.一种方式:

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;
}
Run Code Online (Sandbox Code Playgroud)

我也冒昧地移动enable_if到模板参数.这样就不能通过为两个参数指定类型名来规避SFINAE(尽管可以肯定的是,对于重载运算符来说,它不太可能发生).

另一个很好的事实是,自定义点现在与函数定义本身分离.添加新的迭代只是添加另一个专业化的问题details::writable.

实例