如何用 C++ 编写一个函数,以与容器无关的方式接收某种类型的迭代器作为参数?即
// C# version
void foo(IEnumerable<MyConcreteClass> t)
{
foreach(MyConcreteClass c in t)
{
c.MyFunction();
}
}
阅读有关迭代器的内容后,我似乎应该做这样的事情:
template<MyIter>
void foo(MyIter start, MyIter end, std::input_iterator_tag type)
{
// How would the next part work? Do I do:
while (start != end)
{
MyConcreteClass* c = *start; // this will compile iff the parameter is correct.
c->MyFunction();
start++;
}
在传入无效迭代器类型的情况下(例如 std::unordered_set<MyOtherClass*>::iterator
),我认为使用此方法生成的编译器错误只是我取消引用 start
的行中的某种无效转换错误。 ;相反,我想得到一个错误,表明我实际上传递了错误类型的迭代器。有一个更好的方法吗?我很乐意说“MyIter 必须是来自 MyConcreteClass 容器的迭代器”
顺便说一句,C++11 机制没问题。
最佳答案
如果你愿意,你可以添加类似的内容
static_assert(std::is_convertible<decltype(*start), MyConcreteClass*>::value, "MyIter must be an iterator from a container of MyConcreteClass");
到函数体内的任何地方。
请注意,这与 MyConcreteClass
和 foo
紧密结合,因此,如果您确定需要这样做,那就没问题。但如果你不这样做,你可以对其进行更多的泛化并编写
template<MyIter>
void foo(MyIter start, MyIter end)
{
while (start != end) {
auto c = *start;
c->MyFunction();
// Or instead of the above two statements:
// (*c)->MyFunction();
start++;
}
}
这适用于指向具有 MyFunction
函数的任何类型的指针,因此现在您甚至可以使用 unique_ptr
的容器,而以前则不能。但是,您无法轻松地为此编写断言语句,因此这是一种权衡。 C++ 的传统只是记录函数(例如,“此函数适用于在 operator->
后面具有可用的 MyFunction()
的所有类型”)并让如果违反要求,编译器会出错。
关于c++ - 与容器无关的迭代器参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20308858/