Как добиться перегрузки для контейнеров и итераторов для шаблонной функции? - PullRequest
0 голосов
/ 24 сентября 2019

Я хочу 4 перегрузки функции шаблона.Функция принимает диапазон значений y и другой диапазон значений x.Эти диапазоны могут быть указаны как итераторы или как контейнеры.Если они передаются как контейнеры, функции итератора для контейнера вызываются с помощью begin / end.Для xa существует особый случай, когда прохождение скаляра x будет обрабатываться так, как если бы все 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::vector и double подходит для функции 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);

1 Ответ

2 голосов
/ 24 сентября 2019

Используя 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

...