46

Is it a good approach to use std::ignore for ignoring unused variables?

Suppose I have a function like this:

void func(int i)
{
   //for some reason, I don't need i anymore but I cannot change signature of function    
   std::ignore = i; 
}

Additional Info

This was one example and some answers suggested to use anonymous variables. But how would I do it for other cases, like:

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;
}
Mailerdaimon
  • 6,003
  • 3
  • 35
  • 46
gaurav bharadwaj
  • 1,669
  • 1
  • 12
  • 29
  • 7
    You can cast it to void: `(void)i;` to suppress the warning in pre C++17 code. – Sam Oct 03 '16 at 12:17

7 Answers7

56

std::ignore may work but it is intended to be used for tuples. So you need to include the tuple header and who knows what operations are done for the assignment. This also may break in another c++ version because it was never documented to be used that way.

A better way for this is the C++17 attribute [[maybe_unused]]

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

It places the declaration right at the variable declaration, so you don't have to declare it in an extra line/statement.

The same can be used for local (and local-static) variables

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

And also for many more:

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.

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

As for the people concerned that you can still use the variables after you declare them unused:

Yes, this is possible but (at least with clang) you will get warnings in case you use maybe_unused declared variables.

Hayt
  • 5,210
  • 30
  • 37
  • 2
    @gsamaras I think this is worse than Alexey's answer because this allows you to accidentally shoot yourself in the foot because while OP's intent is that the variable isn't used, this answer doesn't invoke the compiler's help to verify that intent. – Nicu Stiurca Sep 28 '16 at 11:32
  • Check the timestamps @NicuStiurca! :) – gsamaras Sep 28 '16 at 11:43
  • 1
    @NicuStiurca that's why it's called `maybe_unused` ;) Also as we are talking about compiler warnings: Clang generates a warning when you use i. So I see Alexey's as an alternative but not mine as "worse" – Hayt Sep 28 '16 at 11:44
  • Also don't understand why this was added. Commenting out the variable is way cleaner and not ambigious when starting to read and understand a function. – Stephan Dollberg Sep 29 '16 at 07:46
  • 1
    @inf an issue I had where commenting out was not valid was for base classes. I had a base class with a function which did nothing but can be overloaded (as a even notification). So I had all the warnings about unused varaibles. If i commented them out though autocompletion and the IDEs did not show the varaible names anymore and I did not know what they were used for. So I had to manually switch to the header and lookup the names. – Hayt Sep 29 '16 at 07:59
  • @Hayt Then that's a problem with either your IDE or the way the header/source files were set up. I guess you simply had, in your header file, `struct Foo { virtual void foo(int meaningfulName) {} };` so you got the IDE help but also the compiler warning. But if you have `struct Foo { virtual void foo(int meaningfulName); };` in the header and `void Foo::foo(int /*meaningfulName*/) {}` in the source file, then both the IDE and compiler should be happy. Anyway, OP gave no indication this is a concern. – Nicu Stiurca Sep 29 '16 at 15:23
  • @NicuStiurca yeah but they were like 15 functions just like this. And i did not really see a purpose in creating 15 empty function definitions in this just for fixing warnings. But as I said in the comments of alexeys answer I use this approach usually but it still feels like a hack. This is a langauge feature for this which tells the compiler what you intend instead of "abusing" the language – Hayt Sep 29 '16 at 19:09
47

In such case just don't write variable name:

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

@Hayt's answer is good, but uses latest version of C++ which is not always available. Not writing variable name is an old convention to tell a compiler that you don't actually need the variable.

For an updated question I would go for a static instance of a class with needed initialization in a constructor. I say initialization because the only reason I can make for having such function is to initialize some global object.

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

This solution has a small bonus: SomethingInitializer is RAII compliant. So when application terminates destructor is called and it can make deinitialization.

Note, that compiler knows that classes may do something useful in constructor and destructor, so it will not complain for unused variable.

Alexey Guseynov
  • 5,116
  • 1
  • 19
  • 29
  • 3
    You beat me to the punch by about 2 minutes, so giving you my upvote instead of leaving my answer. I will also note that it's perfectly fine if the corresponding header file still contains something like `void func(int i);`. – Nicu Stiurca Sep 28 '16 at 11:28
  • I had some old compilers run into issues with that. I cannot test right now which ones but it was some VS likely. – Hayt Sep 28 '16 at 11:36
  • @Hayt "I had some old compilers"... yet you suggest a C++17 solution? :) – Nicu Stiurca Sep 28 '16 at 11:37
  • well because this answer is compatible for non-c++17 solutions ;) . It seems this may also cause some doxygen issues. See [here](http://stackoverflow.com/questions/1486904/how-do-i-best-silence-a-warning-about-unused-variables) and I have some other scenarios I used that where this solution was kind of ugly but that would be too long for a comment. – Hayt Sep 28 '16 at 11:41
  • Hayt, I agree that if you can stick to C++17, then using attributes is a straightforward solution and straightforward solutions are always preferred ones. But for older compilers hiding variable name is a common solution. That's same as with `a || b && c` which is absolutely correct C++, but many compilers will trigger a warning for it unless you put parenthesis: `a || (b && c)`. – Alexey Guseynov Sep 28 '16 at 12:33
  • yeah I do not disagree with this solution. That is my preferred way too (because of not having c++17 available yet everywhere). I just had at one compiler a problem with this ages ago. – Hayt Sep 28 '16 at 12:57
  • Unnamed parameters won't work if they're used in build-specific macros, such as asserts. – isanae Sep 28 '16 at 15:36
  • Personally I think using /*...*/ is a bad practice, as it is un-nestable. Now try to remark the whole function with additional /*...*/ and you get garbage. – gil_mo Sep 30 '18 at 15:20
16

std::ignore was not intended to be used for this purpose:

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.


I would suggest you not do what you are thinking, since in a real-world big project, it will lead to code that is harder to maintain, where one would look at the prototype of a function, would see that it takes an argument int i, but the function would not need that in reality - doesn't feel nice, does it? :)

Null
  • 1,950
  • 9
  • 30
  • 33
gsamaras
  • 71,951
  • 46
  • 188
  • 305
10

In C++17, attribute [[maybe_unused]] might be used:

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

Previously, as alternative, without removing i from signature (as some documentation tools may require it), there are several ways to silence the warning:

  • casting to void:

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

    It is not fully portable, but that suppresses the warning on most compilers.

  • The "clean" way is to create a dedicated function for that:

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

    and then

    void func(int i)
    {
       Unused(i); // Silence warning for unused variable
    }
    
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Ur approach is good but still do u think std::ignore is having any pitfall – gaurav bharadwaj Sep 28 '16 at 12:03
  • 2
    You are using it without actually using it. Nice :D – CinCout Sep 28 '16 at 12:11
  • I don't see any pitfall, but it seems not be the traditional way to do it. – Jarod42 Sep 28 '16 at 12:12
  • 1
    @gauravbharadwaj The pitfall is obvious and unambiguous: `std::ignore` is only a constant of unspecified type, for the purpose of swallowing unwanted output arguments to `std::tie()`. It is not intended as a general-purpose way of ignoring any other assignment you don't want (so the name is kind of unfortunate). So, if you use it as that, you are writing brittle code that can suddenly break at any moment, or may even be doing things you don't expect behind the scenes. – underscore_d Nov 03 '17 at 19:52
2

I think you have an XY problem here. You don't really care about how to ignore static variables; you just want to call a function once (and only once) in a thread-safe, reentrant manner.

To which I say: have you heard of std::call_once? You should rewrite your method as

#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);
 }
Jacob Manaker
  • 723
  • 4
  • 17
  • I actually don't think that's what the OP wants. – ytoledano Sep 29 '16 at 06:56
  • 2
    The OP has requested how to indicate that he does not want to use a variable; he is just defining it to take advantage of its storage duration. Rather than define a variable and then struggle to indicate that it is not used, writing imperative code without any unused variables is a better solution to his problem. – Jacob Manaker Sep 29 '16 at 14:42
1

Another way to do that is by means of a trailing return type as the following one:

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

If you have more than one variable, you can list them all:

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

And you can still declare your preferred return type if void is not what you want:

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

The advantages of this solution are:

  • Variable name is preserved: as mentioned by others, do not give a name to the variable could not be an option (because of your documentation system, as an example).

  • You won't pollute your function body with useless expressions aimed to silent a few warnings.

  • You don't have to explicitly define support function to do that.

Of course, this doesn't apply to static variables declared in the function body, but you can do something similar when returning from the function (just an example):

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

int main () {}

More ore less the same advantages.

skypjack
  • 49,335
  • 19
  • 95
  • 187
0

I would like to suggest an alternative for those compiling with ARM.

You can use the _attribute_ keyword to assign the "unused" attribute to a variable. Doing so will cause the compiler to not generate any warnings if the variable is not referenced.

You can assign the "unused" attribute to a method parameter in the method declaration. Simply place the attribute keyword immediately following the variable's name along with the "unused" attribute. I have provided an example below.

Example:

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

The documentation can be referenced here.

Don
  • 13
  • 1
  • 4