Вложенные векторы не следуют правилам продвижения. Решение имеет ошибку.

Эта программа добавляет вложенные векторы, но неправильно отображает типы. Я думаю, что std :: plus должен принимать T1 или T2 в зависимости от основных правил продвижения типов. Оригинальная проблема в этом посте (decltype не разрешает вложенные векторы. Как я могу использовать шаблоны для вложенных векторов?).

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-В целом, так что кейс специализации теперь:

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;
};
};
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 Основной шаблон для использования «лучший» тип. Тогда специализация будет использовать первичную, а последняя сейчас занимается продвижением.

Жить на Колиру

1

По вопросам рекламы [email protected]