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

时间:2018-01-02 12:37:31

标签: 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;
}

由于N中的std::array<size_t, N>,专业化失败了。

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

1 个答案:

答案 0 :(得分: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;
}

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

另一个很好的事实是,自定义点现在与函数定义本身分离。添加新的iterables只需要为details::writable添加另一个特化。

Live Example