每个数据结构的迭代器都有不同类型的返回值 operator*()
例如:-
- 最像数组
DataStructure<T>
:返回T&
。 -
std::unordered_map<K,T>
:返回std::pair<const K, T>&
。 -
const std::unordered_map<K,T>
:返回const std::pair<K, T>&
。
如果我的 iterator::operator*()
数据类型应该是什么想要返回更复杂的东西( std::pair
还不够)?
示例
我有一个自定义的 3D 数据结构 Map3D<T>
就像一张 map (int,int,int)->T
。
为了实现上述要求,我创建了一个新类Bundle3D<T>
。
template<class T>class Bundle3D {
//getInternalIndex1D()
//getCoordinate()
//getValue()
};
Map3D<T>
的iterator::operator*
会有这样的签名:-
Bundle3D<T> iterator::operator*(){ ... }
它的用法如下:-
Map3D<float> map;
for(auto& ele:map){ //"ele" has some special type named "Bundle"
int keyInternal1DIndex=ele.getInternalIndex1D();
Vector3Int& key=ele.getCoordinate();
float& value=ele.getValue();
}
效果很好,但我认为我的代码没有标准化。
换句话说,Bundle3D<T>
, getInternalIndex1D()
, getCoordinate()
和getValue()
是我瞎起的名字。
在实际情况中,我创建了很多自定义数据结构来生成如此奇怪的迭代器。
问题
有没有std::
/iterator::operator*()
的返回值的标准类型,当 T&
和std::pair
是不足够的?
我已经怀疑这个问题好几个月了,但又很不愿意问。
如果这个问题需要改进,请评论。
编辑
(澄清这个词标准化 - 这部分是我的主观想法。)
我觉得大多数语言中的所有类型的标准集合,例如:-
-
java.util.Collection/ArrayList
在Java中 -
std::unordered_map/vector
在 C++ 中
它们的迭代器都具有函数 getValue()
的签名或operator*
返回 T
或StandardPair<index,T>
- 没有其他类型。
多年来,我坚信这是我真正应该遵守的规则或强烈的惯例/传统。
必有理由。
但是,我不确定它是什么,因为我可能对 C++ 很陌生。
如果我设计的软件返回一些奇怪的东西(例如上例中的 Bundle3D<T>
),我想我会因为非常规设计而受到严厉的惩罚。 (例如没有 .first
字段)
最佳答案
你现在拥有的一切都还好。我只想指定一件我认为不太 C++ 风格的事情,并且实际上可能会损害您将来的标准化选项。
这是 setter/getter 。显然你对Java有很深的根基,并且公共(public)成员的概念在Java编程中是令人深恶痛绝的,以至于存在“bean”的概念。我不想在这里批评 Java,它是一种很好的语言,有自己很好的习惯用法。
但这是 C++,有它自己的编程习惯。您显然注意到了对 std::pair
内容的直接访问。之所以会这样,是有原因的。一对只是打包在一起的两个项目,这是其行为的总和。 setter/getter 只会妨碍。 :)
不需要它们,因为我们不是在处理捆绑在一起的两个项目的“抽象”,而是我们确实有一个具体的、诚实的 bundle 1。
显然,我们可以捆绑两个以上的元素。这就是为什么我们有 std::tuple
。现在,虽然对元组的所有访问确实都是通过名为 get
的非成员函数进行的,但这只是因为无法为任意大小的包的成员命名。 get
仍然返回对该元素的引用,因此您可以直接访问该包。
这个冗长的阐述很重要,因为即将推出的 C++1z 功能称为 "Structured Bindings" ,依赖于元组和对的标准行为,以及 C++ 程序员如何看待聚合。在此功能下, map 上的迭代将如下所示:
#include <map>
#include <iostream>
std::map<char const*, int> foo()
{
return {
{ "foo", 3 },
{ "bar", 7 },
{ "baz", 1 },
};
}
int main() {
for (auto [key, val] : foo()) {
std:: cout << "( " << key << ", " << val << " )\n";
}
return 0;
}
这同样适用于任何用户定义的数据包。如果成员是公共(public)的,则可以类似地绑定(bind)帖子中您自己的返回值类型:
struct Vector3Int {};
template<class T>
struct Bundle3D {
int internal_index_id;
Vector3Int const &coord;
T &value;
};
int main() {
Vector3Int vec;
float val;
Bundle3D<float> bundle{ 1, vec, val };
auto[ idx_id, coord, value] = bundle;
// coord = {}; // compile error since coord gets the cv qualifer
}
所以我的建议是,将 getter 留给 Java 代码,并使用聚合作为 C++ 的数据束。
1 更正式地说,是一个聚合。
关于c++ - iterator::operator* 的标准接口(interface)返回的内容多于 T& 和 std::pair,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43888016/