容器不可知迭代器参数



如何在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容器中的迭代器"

BTW、C++11机制还可以。

如果你愿意,你可以添加一些类似的东西

static_assert(std::is_convertible<decltype(*start), MyConcreteClass*>::value, "MyIter must be an iterator from a container of MyConcreteClass");

到函数体内部的任何位置。

请注意,这将MyConcreteClassfoo紧密耦合在一起,所以如果您确定要这样做,那么也没关系。但如果你不这样做,你可以将其更多地通用化并编写

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()可用的所有类型"),如果违反要求,则让编译器出错。

对于您的函数,您可以使用以下内容:

template <template <typename...> class Container>
void foo(Container<MyConcreteClass>& container)
{
   for (auto elem : container)
   {
     elem.MyFunction();
   }
}

之后的额外参数的更完整示例:您可以在之前对参数使用类似的工作

template <template <typename...> class Container, typename... Ts>
void foo(Container<MyConcreteClass, Ts...>& container)
{
   for (auto elem : container)
   {
     elem.MyFunction();
   }
}

如果同时使用(before和after),则可能会被视为不明确(我的gcc无法编译)。

最新更新