【问题标题】:How can I determine the actual type of an 'auto' variable如何确定“自动”变量的实际类型
【发布时间】:2013-07-22 23:37:34
【问题描述】:

在此回复中:

https://stackoverflow.com/a/14382318/1676605

这个程序给出:

std::vector<int> vi{ 0, 2, 4 };
std::vector<std::string> vs{ "1", "3", "5", "7" };
for (auto i : redi::zip(vi, vs))
    std::cout << i.get<0>() << ' ' << i.get<1>() << ' ';

我不知道auto i 的类型是什么,这使得重用专业知识和从示例中学习变得更加困难。以下是将auto i 更改为char i 的结果

In function ‘int main()’:|
/data/cbworkspace/TestZip/TestZip.cpp|14|error: cannot convert ‘boost::iterator_facade<boost::zip_iterator<boost::tuples::tuple<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, __gnu_cxx::__normal_iterator<int*, std::vector<int> > > >, boost::tuples::cons<int&, boost::tuples::cons<int&, boost::tuples::null_type> >, boost::random_access_traversal_tag, boost::tuples::cons<int&, boost::tuples::cons<int&, boost::tuples::null_type> >, long int>::reference {aka boost::tuples::cons<int&, boost::tuples::cons<int&, boost::tuples::null_type> >}’ to ‘char’ in initialization|
/data/cbworkspace/TestZip/TestZip.cpp|14|warning: unused variable ‘i’ [-Wunused-variable]|
||=== Build finished: 1 errors, 1 warnings (0 minutes, 0 seconds) ===|

尝试从中找出类型。

有没有办法找出 C++11 中 auto 的变量是什么类型?更清楚地说,我有一个这样的struct

struct EventData
{
    // return value from redi::zip<std::vector<PriceQuote>, std::vector<PriceQuote>> what goes here????? So REDI::Zip is zipping PriceQuote, PriceQuote of bids and asks.
};

struct PriceQuote
{
   double price;
   double size;
};

【问题讨论】:

  • 检查redi::zip返回的参考。
  • (A) 使用 IDE,(B) 如果您对使用它的类型不够了解,请不要使用 auto
  • 如果你不介意在运行时得到答案,你总是可以做类似std::cout &lt;&lt; typeid(i).name() &lt;&lt; std::endl;
  • 你是对的,但至少我可以看出它是某种迭代器
  • 不管是什么类型,重要的是怎么用。

标签: c++ c++11 auto


【解决方案1】:

尝试将 auto 更改为 char 并阅读错误信息。

【讨论】:

  • 错误可能难以阅读,但这是一个有趣的想法
  • 特别是在使用模板时!
  • 查看我对凯西的评论
  • 将它传递给template&lt;class T&gt;unsigned char identify(T&amp;&amp; v) {return v;},它会删除无用的模板内容(除非它可以隐式转换为无符号字符...)
  • 这是天才。
【解决方案2】:

为什么要将该类型放入结构中?它并不是真的被设计成那样使用的(我应该知道,我写了它!)但如有必要,您可以使用 decltypestd::declval 来确定类型(如果我更改实现,它仍然会给出正确的答案redi::zip)

struct EventData
{
  // type returned by redi::zip
  typedef decltype(redi::zip(std::declval<V1>(), std::declval<V2>())) zipper_type;

  // type referred to by zipper_type::iterator
  typedef std::iterator_traits<zipper_type::iterator>::value_type zipped_type;

  zipper_type m_zipper;
};

注意为什么要为struct 创建typedef?这是 C++ 而不是 C,别说了。

我不知道 auto i 是什么类型,这使得重用专业知识和从示例中学习变得更加困难。

习惯了。你知道std::bind返回的类型吗?你知道std::mem_fn返回的类型吗?你知道 lambda 表达式创建的类型吗?不,你不需要知道,你只需要知道它有什么属性以及你可以用它做什么,而不是它叫什么或者它包含什么类型。

【讨论】:

  • 正如我在另一条评论中提到的,我不确定这是否有任何帮助,因为 redi::zip 需要原始范围才能保持活力。
  • 我认为他实际上并不想要该范围,他似乎希望该类型将迭代器取消引用到 zip 范围中。
  • 另外,关于std::bind 和您的其他示例,我们有std::function 用于存储这些正是出于这个原因。
  • @MooingDuck,嗯,你可能是对的类型(虽然他说他想要 "return value from redi::zip" 这显然不同于该类型的@ 987654332@) -- 已更新答案以给出该类型。
  • @MooingDuck,没错,std::function 适用于你知道你可以用它做什么而不是它到底是什么类型的合适类型。
【解决方案3】:

你找到了吗

for (boost::iterator_facade<
       boost::zip_iterator<
         boost::tuples::tuple<std::vector<int>::iterator,
                              std::vector<int>::iterator>
       >,
       boost::tuples::cons<int&, boost::tuples::cons<int&, boost::tuples::null_type> >,
       boost::random_access_traversal_tag,
       boost::tuples::cons<int&, boost::tuples::cons<int&, boost::tuples::null_type> >,
       long int
     >::reference i : redi::zip(vi, vs))
    std::cout << i.get<0>() << ' ' << i.get<1>() << ' ';

更容易理解?

【讨论】:

  • 好点,但是,如何将 redi::zip 的返回值分配给我自己的变量而不使其成为自动变量? typedef struct EventData { /*我在这里放什么? */ }
  • 正如上面其他人所说,它是什么类型并不重要,重要的是你可以用它做什么。仅从示例代码中,我就知道“我可以用它做什么”是在boost::tuple&lt;int, int&gt; 的某种范围内迭代。我会使用一个包含上述元组的容器来存储 std::vector&lt;boost::tuple&lt;int,int&gt;&gt; 并用 boost::range::copy(redi::zip(vi, vs), myvector); 填充它。
  • 太好了,所以现在您正在向不需要它的程序添加副本以便您可以存储它?请参阅我修改后的原始问题。
  • 您明确引用的问题的答案指出:“请参阅 了解适用于 range-base[d] for... 的 zip 函数”所以如果这就是你真的很想:for(auto i: redi::zip(vi, vs)) myvector.push_back(i); 会做到的。我更喜欢算法而不是显式副本。
  • @user1676605: decltype 想和你谈谈。但是,这可能对您没有帮助 - redi::zip 返回一个惰性范围,该范围取决于 原始范围是否处于活动状态。它只是使用迭代器进入那些原始范围,所以如果它们消失了,redi::zip 的返回范围就会悬空。
【解决方案4】:

找出redi::zip() 返回什么的最好方法是查看redi::zip() 返回什么。 =) 我的 IDE 让我可以通过按住 Ctrl 并单击 zip() 直接跳转到它。你的不提供类似的功能吗? 我什至可以将鼠标悬停在 for() 循环中的 zip() 上,并获得一个提供函数签名的工具提示 - 包括返回类型。

无论如何,您都需要查看它以输入您手动替换“auto”的任何内容,并且 auto 具有很大的好处,它可以让您声明无法以其他方式声明的类型(如 lambda 返回,除非这样做decltype 之类的复杂事物,与 auto 具有您不喜欢的相同缺陷)。

当 IDE 更多地支持 C++11 时,您的智能感知会更好地发挥作用,并且会更清楚类型是什么。我敢肯定,在一年或更短的时间内,大多数最新的 IDE 都会在悬停时告诉您 auto 的真实类型。

auto 的收益远大于损失,但是,是的,有一点损失会在良好的 IDE 支持下变得更小。几乎所有事物都有优点和缺点。

【讨论】:

    【解决方案5】:

    答案

    "我如何在编译时确定'auto'变量的实际类型"

    答案:

    尝试编译如下内容:

    auto foo = function_that_returns_unknown_type() // "what type could foo be?"
    int a = foo;
    

    编译器错误消息将告诉您“类型XXX(无论是什么)都无法转换为int”。你有你的类型

    【讨论】:

      【解决方案6】:

      我不同意您的说法,即不知道 i 的类型是“使重用专业知识和从示例中学习变得更加困难”。 i 的类型是“zip 返回的那个东西”。为什么还不够?

      【讨论】:

      • 见我上面对凯西的评论
      • 如果我能说 typedef struct EventData { 不管 redi::zip::returns zip; } 事件数据;所以我建议一个新的 c++11 关键字,“whatever”,它类似于 auto,但在编译时为我计算出返回类型,而不需要分配它。
      • @user1676605:在 C++11 中,您完全可以做到这一点。只是语法不同:decltype(redi::zip(vi,vs)) zip;
      【解决方案7】:

      除了其他答案,我喜欢使用&lt;boost/type_index.hpp&gt;

      int main()
      {
          using namespace std;
          using namespace boost::typeindex;
      
          auto p = std::make_pair(1, 2);
          cout << type_id_with_cvr<decltype(p)>().pretty_name();
      }
      

      哪些输出:

      std::pair<int, int>
      

      你也可以从&lt;typeinfo&gt;使用typeid()

      auto p = std::make_pair(1, 2);
      cout << typeid(p).name() << '\n';
      

      输出不像第一个例子那样容易理解,但仍然:

      St4pairIiiE
      

      【讨论】:

        【解决方案8】:

        Windows:Visual Studio 的内置调试器将为您提供类型信息。

        Linux:在 gdb 中调试代码并在 exe 与范围内的变量中断时提交ptype &lt;varname&gt;。示例输出 - 在这种情况下,我可以将 auto 替换为 vector&lt;uint8_t&gt;::const_iterator 但这并不是特别明显:

        type = class __gnu_cxx::__normal_iterator
                          <unsigned char const*,
                           std::vector<unsigned char,
                                       std::allocator<unsigned char>
                                      > 
                          >
               [with _Iterator = const unsigned char *, 
               _Container = std::vector<unsigned char, std::allocator<unsigned char> >] 
                {
           protected:
               _Iterator _M_current;
        
           public:
             __normal_iterator(void);
             __normal_iterator(const unsigned char * const&);
             reference operator*(void) const;
             _Iterator operator->(void) const;
             __gnu_cxx::__normal_iterator<unsigned char const*, _Container> & operator++(void);
             __gnu_cxx::__normal_iterator<unsigned char const*, _Container> operator++(int);
             __gnu_cxx::__normal_iterator<unsigned char const*, _Container> & operator--(void);
             __gnu_cxx::__normal_iterator<unsigned char const*, _Container> operator--(int);
             reference operator[](difference_type) const;
             __gnu_cxx::__normal_iterator<unsigned char const*, _Container> & operator+=(difference_type);
             __gnu_cxx::__normal_iterator<unsigned char const*, _Container> operator+(difference_type) const;
             __gnu_cxx::__normal_iterator<unsigned char const*, _Container> & operator-=(difference_type);
            __gnu_cxx::__normal_iterator<unsigned char const*, _Container> operator-(difference_type) const;
        
             const unsigned char * const& base(void) const;
             void __normal_iterator<unsigned char*>(const
                                __gnu_cxx::__normal_iterator<unsigned char*, _Container> &);
        
             typedef std::iterator_traits<unsigned char const*>::reference reference;
             typedef _Iterator pointer;
             typedef std::iterator_traits<unsigned char const*>::difference_type difference_type;
             typedef std::iterator_traits<unsigned char const*>::iterator_category iterator_category;
         }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-10-25
          • 1970-01-01
          • 2010-09-28
          • 2016-03-29
          • 2021-03-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多