42

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

附加信息

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

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;
}
4

7 回答 7

50

std::ignore可能有效,但它旨在用于元组。因此,您需要包含元组标头以及谁知道为分配完成了哪些操作。这也可能会在另一个 c++ 版本中中断,因为它从未被记录为以这种方式使用。

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

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

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

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

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

还有更多:

出现在类、typedef、变量、非静态数据成员、函数、枚举或枚举数的声明中。如果编译器对未使用的实体发出警告,则对于声明为 may_unused 的任何实体都会抑制该警告。

请参阅http://en.cppreference.com/w/cpp/language/attributes

至于那些声明变量未使用后仍然可以使用的人:

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

于 2016-09-28T11:20:21.860 回答
46

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

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。因此,当应用程序终止时,会调用析构函数并进行反初始化。

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

于 2016-09-28T11:25:06.717 回答
16

std::ignore不打算用于此目的:

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


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

于 2016-09-28T11:18:01.203 回答
9

在 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
    }
    
于 2016-09-28T11:59:23.200 回答
2

我认为你在这里有一个 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);
 }
于 2016-09-28T16:14:02.387 回答
1

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

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

更多或更少相同的优点。

于 2016-09-28T16:02:22.857 回答
0

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

您可以使用_属性_ 关键字“未使用”属性分配给变量。如果未引用变量,这样做将导致编译器不生成任何警告。

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

例子:

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

文档可以参考这里。

于 2021-04-09T00:42:35.857 回答