如何为模板函数实现容器和迭代器的重载?

How to achieve overloads for containers and iterators for template function?

我想要一个模板函数的 4 个重载。该函数采用一系列值 y 和另一个值范围 x。这些范围可以指定为迭代器或容器。如果作为容器传递,则使用 begin/end 为容器调用迭代器函数。对于 x 存在一种特殊情况,其中传递标量 x 将被视为好像 [begin, end) 范围内的所有 x 都是此值。

#include <iterator>
#include <vector>


// 1) Take iterator [begin, end) for y values and scalar for x
template <typename Iterator>
std::vector<double>
func(Iterator ybegin, Iterator yend, typename Iterator::value_type x = 1.) {}


// 2) take sequence of y values and scalar for x
template <typename Sequence>
std::vector<typename Sequence::value_type> 
func(const Sequence& y, typename Sequence::value_type x = 1.) {
    return func(y.begin(), y.end(), x);
}


// 3) take iterator [begin, end) for y values and iterator [begin, end) for x values
template <typename Iterator1, typename Iterator2>
std::vector<double> 
func(Iterator1 ybegin, Iterator1 yend, Iterator2 xbegin, Iterator2 xend) {}


// 4) take sequence of y values and sequence of x values
template <typename Sequence1, typename Sequence2>
std::vector<double> 
func(const Sequence1& y, const Sequence2& x) {
    return func(y.begin(), y.end(), x.begin(), x.end());
}


int main() {
    std::vector<double> a{4, 5, 6};
    std::vector<int> b{1, 1, 1};
    func(a.begin(), a.end(), 0.2);
    func(a.begin(), a.end(), b.begin(), b.end());
    func(a, 0.2);
    func(a, b);
}

我在上面发布的代码无法编译,因为使用 std::vectordouble 的调用适合函数 2)(正确)和 4)(不正确)。

error: call of overloaded ‘func(std::vector<double>&, double)’ is ambiguous
     func(a, 0.2);
                ^
scratch_1.cpp:33:44: note: candidate: ‘std::vector<typename Sequence::value_type> func(const Sequence&, typename Sequence::value_type) [with Sequence = std::vector<double>; typename Sequence::value_type = double]’
 std::vector<typename Sequence::value_type> func(const Sequence& y,
                                            ^~~~
scratch_1.cpp:50:21: note: candidate: ‘std::vector<double> func(const Sequence1&, const Sequence2&) [with Sequence1 = std::vector<double>; Sequence2 = double]’
 std::vector<double> func(const Sequence1& y, const Sequence2& x) {

如果我使用以下版本的 2) 和 4),我会得到

// 2)
template <typename Sequence>
std::vector<typename Sequence::value_type>
func(const Sequence& y, typename std::enable_if<std::is_scalar<typename Sequence::value_type>::value,
                                                typename Sequence::value_type>::type x = 1.) {
    return func(y.begin(), y.end(), x);
}

// 4)
template <typename Sequence1, typename Sequence2>
std::vector<double>
func(const Sequence1& y,
     const typename std::enable_if<!std::is_scalar<Sequence2>::value, Sequence2>::type& x) {
    return func(y.begin(), y.end(), x.begin(), x.end());
}

error: no matching function for call to ‘func(std::vector<double>&, std::vector<int>&)’ 因为无法推导出第二个向量的类型。

 error: no matching function for call to ‘func(std::vector<double>&, std::vector<int>&)’
     func(a, b);

candidate: ‘template<class Sequence1, class Sequence2> std::vector<double> func(const Sequence1&, const typename std::enable_if<(! std::is_scalar<Sequence2>::value), Sequence2>::type&)’
 std::vector<double> func(const Sequence1& y, const typename
                     ^~~~
note:   template argument deduction/substitution failed:
note:   couldn't deduce template parameter ‘Sequence2’ func(a, b);

使用 is_container,这是我公然偷来的:

// 2) take sequence of y values and scalar for x
template <typename Sequence, 
        std::enable_if_t<is_container<Sequence>::value, int> =0
>
std::vector<typename Sequence::value_type> 
func(const Sequence& y, typename Sequence::value_type x = 1.) {
    return func(y.begin(), y.end(), x);
}

// 4) take sequence of y values and sequence of x values
template <typename Sequence1, typename Sequence2, 
        std::enable_if_t<is_container<Sequence1>::value, int> =0, 
        std::enable_if_t<is_container<Sequence2>::value, int> =0 
>
std::vector<double> 
func(const Sequence1& y, const Sequence2& x) {
    return func(y.begin(), y.end(), x.begin(), x.end());
}

http://coliru.stacked-crooked.com/a/90087c6a4c9b4901