Ошибка при использовании шаблона в классе, используемого впоследствии в функции: нет жизнеспособного конструктора или вывода

#templates

#c #шаблоны

Вопрос:

Я создаю функцию Fold, которая может принимать разные классы, например, Sum, которые определяют тип выполняемой операции.


 #include <iostream>
#include <vector>

#include <list>

template <typename T>
struct Sum {
public:
    auto operator() (T init, std::list<int>::const_iterator first,
                    std::list<int>::const_iterator last) {
        for (auto it = first; it != last;   it) {
            init  = *it;
        }
        return init;
    }
};

template <typename Iterat, typename T, typename Operator>
 T Fold(Iterat first, Iterat last, T init, Operator func) {
    return func(init, first, last);
}


int main() {
    std::list<int> a{1, 2, 3, 6};
    std::cout << Fold(a.cbegin(), a.cend(), 0, Sum()) << std::endl;
    return 0;
}
  

Однако, когда я запустил код, я получил ошибку «нет жизнеспособного конструктора или руководства по выводу для вывода аргументов шаблона из ‘Sum'»

Ошибка может быть устранена двумя способами:

  • Если я использую «int» вместо «template T» в сумме классов.
  • Если я укажу в main() тип, который я хочу использовать, например:

 Fold(a.cbegin(), a.cend(), 0, Sum<int>())
  

Есть ли другие способы что-то сделать с этой ошибкой? Ни одно из двух решений, которые я показал выше, не подходит для моей задачи

Ответ №1:

Аргументы шаблона выводятся из аргументов (функции). Поскольку Sum у него нет аргументов, аргументы шаблона не могут быть выведены. Это объясняется здесь .

Однако не все потеряно. Sum , как класс, не использует параметры шаблона. Только operator() метод делает. Таким образом, вы можете поместить шаблон только в operator() метод и оставить Sum как класс, не являющийся шаблоном.

Например:

 struct Sum {                                              
public:                                                   
    template <typename T>                
    auto operator() (T init, std::list<int>::const_iterator first,
                    std::list<int>::const_iterator last) {
        for (auto it = first; it != last;   it) {         
            init  = *it;                                  
        }                                                 
        return init;                                      
    }                                                     
};                                                        
  

Я бы также зашел так далеко, что создал шаблон итератора, как вы сделали с Fold . Полный пример кода с некоторыми дополнительными примерами использования:

 #include <functional>
#include <iostream>
#include <list>
#include <vector>

struct Sum {
public:
    template <typename T, typename Iterat>
    auto operator() (T init, Iterat first, Iterat last) {
        for (auto it = first; it != last;   it) {
            init  = *it;
        }
        return init;
    }
};

template <typename Iterat, typename T, typename Operator>
 T Fold(Iterat first, Iterat last, T init, Operator func) {
    return func(init, first, last);
}


int main() {
    std::list<int> a{1, 2, 3, 6};
    std::cout << Fold(a.cbegin(), a.cend(), 0, Sum()) << std::endl;
    // init is a float. While the iterators return int.
    std::cout << Fold(a.cbegin(), a.cend(), 0.5 , Sum()) << std::endl;
    std::list<std::string> b{"1", "2", "3", "6"};
    std::cout << Fold(b.cbegin(), b.cend(), std::string(""), Sum()) << std::endl;
    return 0;
}