Std::ignore用于忽略未使用的变量

std::ignore for ignoring unused variable

本文关键字:未使用 变量 ignore 用于 Std      更新时间:2023-10-16

使用std::ignore忽略未使用的变量是一种好方法吗?

假设我有一个这样的函数:

void func(int i)
{
   //for some reason, I don't need i anymore but I cannot change signature of function    
   std::ignore = i; 
}
<<p> 附加信息/strong>

这是一个例子,一些答案建议使用匿名变量。但是对于其他情况,我该怎么做呢,比如:

int Thread_UnSafe_func_returnSomething():
void func()
{
   // To make it thread safe
   // Also it is required to call only once
   static int i = Thread_UnSafe_func_returnSomething();
   std::ignore = i;
}

std::ignore可以工作,但它打算用于元组。因此,您需要包含元组头文件,谁知道为赋值执行了什么操作。这在另一个c++版本中也可能会被破坏,因为文档中从来没有这样使用过。

一个更好的方法是c++ 17属性[[maybe_unused]]
void func([[maybe_unused]] int i)
{
}

它将声明放在变量声明处,因此您不必在额外的行/语句中声明它。

同样可以用于本地(和本地-静态)变量

...
[[maybe_unused]] static int a = something();
...

还有更多:

出现在类、类型定义、变量、a的声明中非静态数据成员、函数、枚举或枚举数。如果编译器对未使用的实体发出警告,该警告是禁止任何声明为maybe_unused的实体

见http://en.cppreference.com/w/cpp/language/attributes

对于那些在声明变量未使用后仍然可以使用它们的人:

是的,这是可能的,但(至少与clang)你会得到警告,如果你使用maybe_unused声明的变量。

在这种情况下就不要写变量名:
void func(int /*i*/)
{
    ...
}

@Hayt的答案很好,但使用的是最新版本的c++,而这并不总是可用的。不写变量名是一个古老的惯例,用来告诉编译器你实际上不需要这个变量。

对于一个更新的问题,我会选择在构造函数中初始化类的静态实例。我之所以说初始化,是因为我拥有这样一个函数的唯一理由就是初始化某个全局对象。

class SomethingInitializer {
public:
    SomethingInitializer() {
        func_returnSomething();
    }
    ~SomethingInitializer() {
        // Note, that when you initialize something it is a good practice to deinitialize it at the end, and here is a proper place for that.
    }
};
void func() {
    static SomethingInitializer initializer;
}

这个解决方案有一个小好处:SomethingInitializer是RAII兼容的。因此,当应用程序终止时,调用析构函数,它可以取消初始化。

注意,编译器知道类可以在构造函数和析构函数中做一些有用的事情,所以它不会抱怨未使用的变量。

std::ignore不是用于此目的:

未指定类型的对象,任何值都可以赋给它而不产生任何影响。用于在解包std::元组时与std::tie一起使用,作为未使用参数的占位符。


我建议你不要做你想做的事,因为在现实世界的大项目中,它会导致更难维护的代码,在那里人们会看到函数的原型,会看到它需要一个参数int i,但函数在现实中不需要它-感觉不舒服,不是吗?:)

在c++ 17中,可以使用属性[[maybe_unused]]:

void func([[maybe_unused]]int i)
{
    // ...
}

以前,作为替代方案,不需要从签名中删除i(因为某些文档工具可能需要它),有几种方法可以沉默警告:

  • cast to void:

    void func(int i)
    {
       static_cast<void>(i); // Silence warning for unused variable
    }
    

    它不是完全可移植的,但这在大多数编译器上抑制了警告。

  • "clean"方法是创建一个专门的函数:

    template <typename T>
    void Unused(T&& /*No name*/) { /*Empty*/ }
    

    void func(int i)
    {
       Unused(i); // Silence warning for unused variable
    }
    

我想你这里有XY问题。你并不关心如何忽略静态变量;您只希望以线程安全的、可重入的方式调用函数一次(且仅一次)。

我说:你听说过std::call_once吗?你应该把你的方法重写为

#include <mutex>
int Thread_UnSafe_func_returnSomething();
void func(void)
{
      //To make it thread safe
     static std::once_flag initComplete;
     std::call_once(initComplete, func_returnSomething);
 }

另一种方法是使用尾随返回类型,如下所示:

auto func(int i) -> decltype(void(i)) {}
int main() {}

如果你有多个变量,你可以列出它们:

auto func(int i, int j) -> decltype(void(i), void(j)) {}
int main() {}

如果void不是你想要的,你仍然可以声明你的首选返回类型:

auto func(int i) -> decltype(void(i), int{}) { return 42; }
int main() {}

这个解决方案的优点是:

  • 变量名被保留:正如其他人所提到的,不要给不能作为选项的变量命名(例如,因为你的文档系统)。

  • 你不会用无用的表达式来污染你的函数体,这些表达式旨在沉默一些警告。

  • 你不需要明确定义支持函数来做这些

当然,这不适用于在函数体中声明的静态变量,但是您可以在从函数返回时做类似的事情(只是一个示例):
int f() {
    static int i = 0;
    static int j = 0;
    return void(i), void(j), 42;
}
int main () {}

我想为那些用ARM编译的人提供一个替代方案。

您可以使用_属性_关键字来分配"未使用"属性设置为变量。这样做将导致编译器在变量未被引用时不生成任何警告。

您可以分配"未使用的";属性设置为方法声明中的方法参数。只需将属性关键字紧接在变量名后面,并加上"未使用";属性。我在下面提供了一个例子。

的例子:

void someFunc(int x __attribute__((unused)) );

文档可以在这里引用