13

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

4

5 回答 5

6

您可以定义一个宏:

#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:关闭编译器警告)。

Boost 标头<boost/core/ignore_unused.hpp>(Boost >= 1.56) 出于相同目的定义了函数 template boost::ignore_unused()

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

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

类似的问题:


PS C++17似乎正在获得一个[[maybe_unused]]属性,以提供一种声明未使用变量的标准方式。

于 2014-02-15T16:10:09.877 回答
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

于 2014-02-15T03:59:24.160 回答
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) );
于 2014-02-15T04:23:29.840 回答
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)) { ... }
于 2015-05-19T21:19:15.947 回答
0

我看到你用c++11标记了你的问题,但是如果你打算有一天切换到c++17,你可以使用该maybe_unused属性来描述场景:

for( const auto &[[maybe_unused]] item : *obj->items() )
    Foo( ... );
于 2019-12-18T06:46:05.060 回答