基于范围的for循环中未命名的循环变量?

时间:2014-02-15 01:38:30

标签: c++ c++11 foreach

有没有办法不在基于范围的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循环。

5 个答案:

答案 0 :(得分:5)

您始终可以明确声明该变量在循环体中保证未使用:

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

答案 1 :(得分:5)

您可以定义一个宏:

#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;
}
...

适用于所有编译器,不应有任何开销(Mailbag: Shutting up compiler warnings)。

Boost标头<boost/core/ignore_unused.hpp>(Boost&gt; = 1.56)为了相同的目的定义了函数模板boost::ignore_unused()

使用C ++ 11 std::ignore也是一个不错的选择:

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

类似的问题:


PS C ++ 17 seems to be getting一个[[maybe_unused]]属性,用于提供声明未使用变量的标准方法。

答案 2 :(得分:4)

我认为因此使用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) );

答案 3 :(得分:0)

一个选择是利用编译器通常不会在未使用的变量具有非平凡的析构函数时发出警告的事实,并编写一个通用的模板化包装器来吃掉迭代的实际值,并返回虚拟对象。像这样:

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)) { ... }

答案 4 :(得分:0)

我看到您用 c ++ 11 标记了您的问题,但是如果您打算改用 c ++ 17 ,则可以使用{{3 }}属性用于所描述的场景:

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