web-dev-qa-db-ja.com

未使用の変数を無視するためのstd :: ignore

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

追加情報

これは1つの例であり、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;
}
35

そのような場合、変数名を書かないでください:

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に準拠しています。そのため、アプリケーションが終了するとデストラクタが呼び出され、初期化を解除できます。

コンパイラは、クラスがコンストラクタとデストラクタで何か有用なことをすることを知っているため、未使用の変数について文句を言わないことに注意してください。

41
Alexey Guseynov

std::ignoreは機能する可能性がありますが、タプルに使用することを目的としています。そのため、Tupleヘッダーを含める必要があります。また、割り当てに対してどの操作が行われるかを知っている必要があります。また、この方法で使用することが文書化されていないため、これは別のc ++バージョンでも破損する可能性があります。

これのためのより良い方法は、C++ 17属性[[maybe_unused]]です

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

宣言を変数宣言に配置するため、余分な行/ステートメントで宣言する必要はありません。

ローカル(およびローカル静的)変数にも同じことが使用できます。

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

また、さらに多くの場合:

クラス、typedef、変数、非静的データメンバー、関数、列挙、または列挙子の宣言に表示されます。コンパイラが未使用のエンティティに対して警告を発行する場合、maybe_unusedとして宣言されたエンティティに対してその警告は抑制されます。

http://en.cppreference.com/w/cpp/language/attributes を参照してください

変数を未使用と宣言した後でも変数を使用できることを懸念している人々については:

はい、これは可能ですが、(少なくともclangでは)maybe_unused宣言された変数を使用すると警告が表示されます。

38
Hayt

std :: ignore は、この目的で使用することを意図していませんでした。

任意の値を効果なしで割り当てることができる、タイプが指定されていないオブジェクト。使用されない引数のプレースホルダーとして、std :: Tupleをアンパックするときにstd :: tieとともに使用することを目的としています。


私はあなたがnotしないことをお勧めします関数のプロトタイプを見ると、引数int i、しかし、関数は実際にはそれを必要としません-ニースを感じませんか? :)

15
gsamaras

別の方法として、署名からiを削除せずに(一部のドキュメント作成ツールで必要になる場合があります)、警告をサイレントにする方法がいくつかあります。

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

完全な移植性はありませんが、ほとんどのコンパイラーでは警告が表示されません。

クリーンな方法は、そのための専用関数を作成することです:

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

その後

void func(int i)
{
   Unused(i); // Silent warning for unused variable
}
8
Jarod42

ここでXYの問題があると思います。静的変数を無視する方法はあまり気にしません。スレッドセーフでリエントラントな方法で関数を1回だけ呼び出します。

私が言うには: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);
 }
2
Jacob Manaker

それを行う別の方法は、次のような末尾の戻り値型を使用することです。

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

多かれ少なかれ同じ利点。

1
skypjack