decltype 不解析嵌套向量.如何将模板用于嵌套向量
decltype does not resolve nested vectors. How can I use templates for nested vectors?
我正在尝试重载 + 运算符来处理嵌套向量。 我以为该函数会调用自己,直到嵌套向量解析为基本类型,但是当我编译它时,我得到了大量的错误列表。 我定义的向量运算适用于基本类型,但不适用于可变数量的嵌套向量。 唯一适用于嵌套向量的操作是<<运算符。
主.cpp
#include <iostream>
#include <vector>
#include <algorithm>
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>
auto operator+(const std::vector<T1>& l, const std::vector<T2>& r)
-> std::vector<decltype((l[0] + r[0]))>{
typedef decltype((l[0] + r[0])) type;
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), std::plus<type>());
else
std::transform(l.begin(), l.end(), r.begin(), std::back_inserter(ans), std::plus<type>());
return ans;
};
int main(){
std::vector<std::vector<int>> vecvec = {{1,2,3},{4,5,6},{7,8,9}};
std::vector<int> vec = {1,2,3};
//Both output statements compile
std::cout << vec << std::endl;
std::cout << vecvec << std::endl;
//Does not compile
vecvec = vecvec + vecvec;
//Does compile
vec = vec + vec;
return 0;
}
现在我无法使用嵌套向量进行类型升级。 我想我需要 std::p lus T1 或 std::p lus T2,具体取决于促销规则。
template <typename T1, typename T2>
struct Add : std::plus<T1> { };//<- Here
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);
}
我试过这个,得到了 2 而不是 2.5 的输出。
int main(){
p(int) e = {1};
p(double) q = {1.5};
std::cout << (e + q) << std::endl;
return 0;
}
您遇到的问题与名称查找有关。您正在对此处的operator+
进行非限定名称查找:
template<typename T1, typename T2>
auto operator+(const std::vector<T1>& l, const std::vector<T2>& r)
-> std::vector<decltype((l[0] + r[0]))> {
^^^^^^^^^^^^^
来自 [basic.scope.pdecl]:
名称的声明点紧接在其完整声明符之后(第 8 条)之前 初始值设定项(如果有)
在该函数中,"完整声明符"包括尾随返回类型。因此,在声明符之后,您的operator+
模板不会在范围内。也就是说,{
另一个问题是std::plus
. std::plus
永远不会找到您的operator+
,因为在定义std::plus
时它还不存在。
在 C++14 中,最简单的解决方案是删除尾随返回类型(无论如何都会正确推断它)并将std::plus
替换为简单的 lambda:
auto plus = [](const type& lhs, const type& rhs) { return lhs + rhs; };
如果没有 C++14,则必须将所有内容转发到另一个函数,以便名称查找可以成功。您可以使用 ADL 技巧,但我认为模板更容易理解。这是一个可行的解决方案:
template <typename T1, typename T2>
struct Add : std::plus<T1> { };
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);
}
我在这里的另一个答案解释了为什么你的方法失败了,以及一种可能的解决方案。我只是想到了一个我认为值得分享的简单得多的。
问题是你不能使用尾随返回类型,因为函数名称本身还没有在范围内,所以你不能以这种方式使用递归。但是,没有什么可以阻止您编写元函数来确定返回类型应该是什么。该元函数非常简单:
template <typename T1, typename T2>
struct nested_common_type :std::common_type<T1, T2> { };
template <typename T1, typename T2>
struct nested_common_type<std::vector<T1>, std::vector<T2>> {
using type = std::vector<typename nested_common_type<T1,T2>::type>;
};
template <typename T1, typename T2>
using vector_common_type_t = std::vector<typename nested_common_type<T1,T2>::type>;
一旦我们有了返回类型,我们就可以只编写一个正常的operator+
:
template <typename T1, typename T2,
typename R = vector_common_type_t<T1,T2>>
R operator+(const std::vector<T1>& l, const std::vector<T2>& r)
{
R ans;
std::transform(l.begin(),
l.begin() + std::min(l.size(), r.size()),
r.begin(),
std::back_inserter(ans),
[](const T1& lhs, const T2& rhs){ return lhs + rhs; });
return ans;
}
- 选择和修改嵌套向量中的条目的最佳实践
- 嵌套向量的缺点是什么?
- 删除嵌套向量中具有remove_if的元素
- 在循环访问嵌套向量时删除元素
- C++:清除嵌套向量会导致奇怪的结果
- 类字符串和嵌套向量C
- 如何在C 中打印出嵌套向量的内容
- 使用嵌套向量动态分配方阵
- 在嵌套向量C 中获取特定元素
- C++崩溃:push_back嵌套向量
- 初始化嵌套向量的大小
- 针对大型嵌套向量的高效内存分配
- 初始化具有预留容量的嵌套向量的子向量
- 如何获取嵌套向量的尺寸(嵌套性)(不是大小)
- 如何创建一个完全动态的嵌套向量
- 是在连续空间中分配的嵌套向量
- 如何在嵌套向量中获取元素类型
- 使用具有嵌套向量的迭代器的意外行为
- 2 个对象的 STL 嵌套向量
- 嵌套c++向量的重新定位