簡體   English   中英

基於范圍的for循環中的未命名循環變量?

[英]Unnamed loop variable in range-based for loop?

有什么方法可以在基於范圍的 for 循環中不“使用”循環變量,同時避免編譯器警告它未被使用?

對於上下文,我正在嘗試執行以下操作。 我已經啟用了“將警告視為錯誤”,並且我寧願不要像在某處毫無意義地提及它來強制“使用”變量那樣進行黑客攻擊。

size_t getSize(const std::forward_list &list)
{
  size_t count = 0;
  for (auto & : list) // compile error, but if i do "auto &i" here, MSVC
                      // complains (reasonably) that i is unused
  {
    ++count;
  }
  return count;
}

我知道還有其他方法可以做到這一點,但為了論證,我需要使用基於范圍的 for 循環。

您可以定義一個宏:

#if defined(__GNUC__)
#  define UNUSED __attribute__ ((unused))
#elif defined(_MSC_VER)
#  define UNUSED __pragma(warning(suppress:4100))
#else
#  define UNUSED
#endif

...
for (auto &dummy UNUSED : list)
{
  ++count;
}
...

它適用於 GCC 和 CLANG(對 MSVC 不太確定……我似乎記得 MSVC 將禁用文件其余部分的警告)。

還:

template<class T> void unused(const T &) {}
...
for (auto &dummy : list)
{
  unused(dummy);

  ++count;
}
...

適用於所有編譯器,不應該有任何開銷( 郵袋:關閉編譯器警告)。

Boost 頭文件<boost/core/ignore_unused.hpp> (Boost >= 1.56) 出於同樣的目的定義了函數模板boost::ignore_unused()

對於 C++11, std::ignore也是一個不錯的選擇:

{
  std::ignore = dummy;
  // ...
}

類似問題:


PS C++17似乎獲得[[maybe_unused]]屬性來提供聲明未使用變量的標准方法。

您始終可以明確聲明該變量在循環體中保證未使用:

ptrdiff_t size( std::forward_list const& list )
{
    ptrdiff_t count = 0;
    for( auto& dummy : list ) 
    {
        (void) dummy; struct dummy;    // Wrap this in a macro if you want.
        // Here everybody including compiler knows that dummy isn't used and can't be used.

        ++count;
    }
    return count;
}

然而,上面的內容遠不如簡單地使用普通的for循環那么清楚。

更不用說簡單地調用size

我認為出於這個原因使用std::for_each ,就像這樣:

template<typename T>
std::size_t  get_size(std::forward_list<T> const& list)
{
     std::size_t count = 0;
     std::for_each(begin(list), end(list), [&count](T const& ){++count;} );
     return count;
}

但是,如果您要獲取任何容器的大小,請使用std::distance

   std::size_t count = std::distance(begin(list), end(list) );

一種選擇是利用這樣一個事實,即編譯器在具有非平凡的析構函數時通常不會警告未使用的變量,並編寫一個通用的模板化包裝器來處理您正在迭代的實際值,並返回虛擬對象。 像這樣的東西:

template <class RangeType>
class UnusedRange {
public:
  UnusedRange(RangeType& wrapped_range) : wrapped_range_(wrapped_range) {}
  // Explicit destructor makes compiler not complain about unused vars.
  class UnusedVal { public: ~UnusedVal() {} };
  class Iterator {
  public:
    typedef decltype(((RangeType*)nullptr)->begin()) WrappedIteratorType;
    Iterator(WrappedIteratorType wrapped_it) : wrapped_it_(wrapped_it) {}
    const Iterator& operator++() { ++wrapped_it_; return *this; }
    bool operator!=(const Iterator& other) { return wrapped_it_ != other.wrapped_it_; }
    UnusedVal operator*() { return UnusedVal(); }
  private:
    WrappedIteratorType wrapped_it_;
  };
  Iterator begin() { return Iterator(wrapped_range_.begin()); }
  Iterator end() { return Iterator(wrapped_range_.end()); }
private:
  RangeType& wrapped_range_;
};
template <class RangeType>
UnusedRange<RangeType> Unused(RangeType& range) {
  return UnusedRange<RangeType>(range);
}

你可以這樣使用它:

for (auto unused : Unused(foo)) { ... }

我看到你用c++11標記了你的問題,但如果你打算有一天切換到c++17,你可以在描述的場景中使用maybe_unused屬性:

for( const auto &[[maybe_unused]] item : *obj->items() )
    Foo( ... );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM