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

std::ignore for ignoring unused variable

使用 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; 
}

附加信息

这是一个示例,一些答案建议使用 anonymous 变量。但是对于其他情况我会怎么做,比如:

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 不打算用于此目的:

An object of unspecified type such that any value can be assigned to it with no effect. Intended for use with std::tie when unpacking a std::tuple, as a placeholder for the arguments that are not used.


我建议你不要按照你的想法去做,因为在现实世界的大项目中,它会导致代码更难维护,看起来在一个函数的原型中,会看到它接受一个参数 int i,但实际上该函数不需要它——感觉不太好,是吗? :)

std::ignore 可能有效,但它旨在用于元组。所以你需要包括元组头,谁知道为赋值做了什么操作。这也可能会破坏另一个 c++ 版本,因为从未记录过以这种方式使用它。

更好的方法是 C++17 属性 [[maybe_unused]]

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

它将声明放在变量声明的右边,因此您不必在额外的 line/statement 中声明它。

同样可以用于局部(和局部静态)变量

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

还有更多:

Appears in the declaration of a class, a typedef­, a variable, a non­static data member, a function, an enumeration, or an enumerator. If the compiler issues warnings on unused entities, that warning is suppressed for any entity declared maybe_unused.

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

关于声明变量未使用后仍然可以使用的相关人士:

是的,这是可能的,但是(至少在 clang 的情况下)如果您使用 maybe_unused 声明的变量,您将收到警告。

在这种情况下不要写变量名:

void func(int /*i*/)
{
    ...
}

@Hayt 的回答很好,但是使用了并不总是可用的最新版本的 C++。不写变量名是告诉编译器您实际上不需要该变量的旧约定。

对于更新的问题,我会选择 class 的静态实例,并在构造函数中进行必要的初始化。我说初始化是因为我可以为拥有这样的功能而做的唯一原因是初始化一些全局对象。

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 兼容的。所以当应用程序终止时,析构函数被调用,它可以进行反初始化。

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

在 C++17 中,可能会使用属性 [[maybe_unused]]

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

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

  • 转换为 void:

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

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

  • “干净”的方法是为此创建一个专用函数:

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

    然后

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

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

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

如果您有多个变量,您可以将它们全部列出:

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

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

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

这个解决方案的优点是:

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

  • 您不会用旨在消除一些警告的无用表达式污染您的函数体。

  • 您不必明确定义支持函数即可。

当然,这不适用于在函数体中声明的静态变量,但您可以在从函数 returning 时做类似的事情(只是一个例子):

int f() {
    static int i = 0;
    static int j = 0;
    return void(i), void(j), 42;
}

int main () {}

更多或更少相同的优势。

我认为你在这里遇到了 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);
 }

我想为那些使用 ARM 编译的人建议一个替代方案。

您可以使用_attribute_ keyword to assign the "unused" attribute 给一个变量。这样做会导致编译器在未引用变量时不会生成任何警告。

您可以在方法声明中将“未使用”属性分配给方法参数。只需将属性关键字与“未使用”属性一起紧跟在变量名称之后。我在下面提供了一个示例。

示例:

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

文档可以参考here.