2015-06-16 4 views
1

Эта программа добавляет вложенные векторы, но не поддерживает типы правильно. Я думаю, std :: plus нужно принимать в T1 или T2 в зависимости от правил продвижения основного типа. Оригинальная проблема заключается в этом сообщении (decltype does not resolve nested vectors. How can I use templates for nested vectors?).Вложенные векторы не соответствуют правилам продвижения. У решения есть ошибка.

main.cpp

#include <algorithm> 
#include <iostream> 
#include <vector> 

template<typename T1> 
std::ostream& operator<<(std::ostream& stream, std::vector<T1> r){ 
    if(r.size() == 0){ 
     return stream; 
    } 
    else{ 
     stream << "("; 
     for(int i = 0; i < r.size(); i++){ 
      if(i < (r.size() - 1)){ 
       stream << r[i] << ", "; 
      } 
      else{ 
       stream << r[i] << ")"; 
      } 
     } 
    } 
    return stream; 
}; 

template <typename T1, typename T2> 
struct Add : std::plus<T1> { };//<-Here T1 or T2 depending on their types. 

template <typename T1, typename T2> 
struct Add<std::vector<T1>, std::vector<T2>> 
{ 
    auto operator()(const std::vector<T1>& l, const std::vector<T2>& r) 
     -> std::vector<decltype(Add<T1,T2>{}(l[0], r[0]))> 
    { 
     using type = decltype(Add<T1,T2>{}(l[0], r[0])); 
     std::vector<type> ans; 

     if(l.size() == std::max(l.size(),r.size())) 
      std::transform(r.begin(), r.end(), l.begin(), std::back_inserter(ans), Add<T1,T2>{}); 
     else 
      std::transform(l.begin(), l.end(), r.begin(), std::back_inserter(ans), Add<T1,T2>{}); 
     return ans; 
    }; 
}; 

template <typename T1, typename T2> 
auto operator+(const std::vector<T1>& lhs, const std::vector<T2>& rhs) 
    -> decltype(Add<std::vector<T1>, std::vector<T2>>{}(lhs, rhs)) 
{ 
    return Add<std::vector<T1>, std::vector<T2>>{}(lhs, rhs); 
} 

int main(){ 
    std::vector<int> e = {1}; 
    std::vector<double> q = {1.5}; 

    //Incorrect result = 2 
    std::cout << (e + q) << std::endl; 
    //Correct result = 2.5 
    std::cout << (q + e) << std::endl; 

    return 0; 
} 

ответ

1

Есть две проблемы в коде (что я неправильно в моем ответе на ваш первоначальный вопрос). Первый, как упоминалось в пункте vsoftco, использует std::common_type для базового футляра.

Вторая ошибка. Рассмотрим это, если заявление:

if(l.size() == std::max(l.size(),r.size())) 
     std::transform(r.begin(), r.end(), l.begin(), std::back_inserter(ans), 
         Add<T1,T2>{}); 
    else 
     std::transform(l.begin(), l.end(), r.begin(), std::back_inserter(ans), 
         Add<T1,T2>{}); 

Add<T1,T2>::operator(), в частичной специализации случае, принимает два аргумента: std::vector<T1> и std::vector<T2>, в таком порядке. Но в двух ветвях заявления if мы фактически вызываем их в разных порядках. В true ветви, мы называем их в обратном порядке, так что просто надо инвертировать порядок в шаблоне:

if(l.size() == std::max(l.size(),r.size())) 
     std::transform(r.begin(), r.end(), l.begin(), std::back_inserter(ans), 
         Add<T2,T1>{}); 

Если на самом деле просто удалить if -statement совсем так, что дело специализации сейчас:

template <typename T1, typename T2> 
struct Add<std::vector<T1>, std::vector<T2>> 
{ 
    using R = decltype(Add<T1,T2>{}(std::declval<T1>(), std::declval<T2>())); 

    std::vector<R> operator()(const std::vector<T1>& l, const std::vector<T2>& r) 
    { 
     std::vector<R> ans; 

     std::transform(l.begin(), 
         l.begin() + std::min(l.size(), r.size()), 
         r.begin(), 
         std::back_inserter(ans), 
         Add<T1,T2>{}); 
     return ans; 
    }; 
}; 
+0

Это работает сейчас :) – dylan

1

Использование std::common_type при определении основного шаблона Add<>, как это (должно #include <type_traits>):

template <typename T1, typename T2> 
struct Add : std::plus<typename std::common_type<T1,T2>::type> { };//<-Here T1 or T2 depending on their types. 

Вы в основном рассказать Add основной шаблон использовать "лучший" тип. Тогда специализация будет использовать первичную, а последняя теперь будет заниматься продвижением по службе.

Live on Coliru

+0

Я пробовал это. Я просто забыл имя. – dylan

+0

@dylan Итак, разве это не работает? – vsoftco

+0

Да, это действительно работает. Почему вы должны включать имя типа. – dylan

Смежные вопросы