【问题标题】:How to create iterator without type names?如何创建没有类型名称的迭代器?
【发布时间】:2015-03-13 14:00:52
【问题描述】:

例如,我有一个std::map<int, string> _m;,我想遍历它。 所以我必须写这样的东西:std::map<int, string>::iterator it = _m.begin()

问题是是否可以在不使用类型名称的情况下创建该迭代器。编译器在创建迭代器的那一刻就知道_m的类型,那我为什么要自己写这些类型呢?

更新 我忘了说我必须使用旧的 C++ 标准。

【问题讨论】:

  • 除非你使用 C++11,否则你不能这样做。您可以创建一个 typedef,这样您就不必在每次需要创建该类型的迭代器时都键入 std::map<int, string>::iterator
  • “我必须使用旧的 C++ 标准”——那么你就错过了很多好东西。包括这样做的能力。

标签: c++ templates iterator std c++03


【解决方案1】:

你在auto关键字之后:

auto it = _m.begin();

编译器在创建迭代器的那一刻就知道_m的类型,那我为什么要自己写这些类型呢?

是的,这就是导致引入auto确切逻辑。

如果你不能使用 C++11,你就会被 typedef 这样的东西困住。引入auto 的新标准的全部原因在于您面临的确切问题 - 不得不一直手动写出长类型名称很尴尬。

typedef std::map<int, string>::iterator map_itr;

map_itr it = _m.begin();

【讨论】:

  • 如果忘了说我必须使用旧的 C++ 标准,我很抱歉
  • 那么,不。引入auto 关键字的全部原因是总是输入std::map&lt;int, string&gt;::iterator it 之类的东西很麻烦。除非你想开始对它进行类型定义,否则你会被它困住。
  • 是的,我知道 typedef 语法,但它不能解决这个特殊问题。如果有一天 map veriable 的定义发生了变化,那么我们也必须更改 typedef。我想知道是否有一些“旧版本的汽车”或至少一些肮脏的黑客来实现这种行为,但感谢您的帮助。
  • 我建议使用非会员 begin()/end() (解释见此herbsutter.com/elements-of-modern-c-style
  • @SkySurfer 那你就错用了typedef typedef 本身应该是你类型的真实来源。其他一切都应该使用 typedef。如果您的类型发生变化,您应该更改您的typedef,仅此而已。否则,请听:我告诉你,C++11 引入auto 的全部原因是为了解决这个问题。显然在此之前没有好的解决方案,否则他们不会在语言中添加auto。您所寻求的解决方案auto 关键字,但您不能使用它,所以不要再要求确切的解决方案了。它在 C++11 之前不存在。
【解决方案2】:

既然您指定您将时间锁定到 C++98,那么您所拥有的最好的就是 BOOST_AUTO 背后的任何黑魔法。

#include <boost/typeof/typeof.hpp>
#include <map>
#include <string>

int main()
{
     std::map<int, std::string> m;
     BOOST_AUTO(it, m.begin());
}

BOOST_FOREACH 的创建与处理循环类似,无需指定迭代器类型。

#include <boost/foreach.hpp>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    // populate v...

    BOOST_FOREACH(int const &i, v)
    {
        std::cout << i << "\n";
    }
}

【讨论】:

    【解决方案3】:

    其实可以通过模板函数实现:

    template <typename ITERATORTYPE> void myfunc(ITERATORTYPE it) {
        //.. do whatever you want with your it
    }
    

    然后调用模板:

    myfunc(_m.begin());
    

    【讨论】:

      【解决方案4】:

      如果您坚持使用 C++03,那么如果您真的需要它,则没有办法在不拼写的情况下引用该类型。您可以做的最好的事情是引入typedef(或更多),这样您只需键入一次长类型:

      typedef std::map<int, string> TypeOfM;
      typedef TypeOfM::iterator MIterator;
      TypeOfM _m;
      

      但是,当您使用标准库算法时,您不必显式命名迭代器:

      std::for_each(_m.begin(), _m.end(), /* a functor */);
      

      如果 Boost 是一个选项,并且您真的只想要迭代,您也可以使用 Boost.Foreach。不幸的是,这仍然需要一个 typedef,因为 mapvalue_type 是一对,因此包含一个 , 会导致预处理器出错:

      typedef std::pair<const int, string> Pair;
      BOOST_FOREACH(const Pair &p, _m)
      {
        // Do whatever you need
      }
      

      【讨论】:

        【解决方案5】:

        由于您尝试对其进行迭代,您可以尝试&lt;algorithm&gt;s 之一,例如std::for_each 并传递一个函数

        【讨论】:

          【解决方案6】:

          最好的通用方法是使用 C++11 的 auto 关键字作为类型。在以后的版本中,这可以在没有任何类型信息的情况下使用基于范围的循环做得更好。

          for (it : _m) {
              /* ... */
          }
          

          如果您坚持使用旧版本,缩短类型名的唯一方法是创建一个模板。不过,这可能比写名字更复杂。类似的东西:

          template <typename T> 
          void do_foo(T it, T end) {
              for (; it < end; ++it) {
                  /* ... */
              }
           }
          
           do_foo(_m.begin(), _m.end());
          

          如果包装你的算法不是这样,你也可以使用 typedef 来缩短它,但你仍然需要输入一次名称。

          【讨论】:

          • C++11 引入了 auto 和基于范围的 for 循环。您的回答听起来好像后者来得较晚。
          猜你喜欢
          • 1970-01-01
          • 2011-05-14
          • 2019-05-05
          • 2019-01-13
          • 2014-09-18
          • 2015-12-24
          • 2012-05-10
          • 1970-01-01
          • 2016-09-23
          相关资源
          最近更新 更多