web-dev-qa-db-ja.com

C ++ 11の未使用パラメーター

C++ 03以前では、未使用のパラメーターに関するコンパイラ警告を無効にするために、通常、次のコードを使用します。

#define UNUSED(expr) do { (void)(expr); } while (0)

例えば

int main(int argc, char *argv[])
{
    UNUSED(argc);
    UNUSED(argv);

    return 0;
}

しかし、マクロはc ++のベストプラクティスではありません。 c ++ 11標準でより良い解決策はありますか?マクロを取り除くことができますか?

全てに感謝!

75
inkooboo

そのために空のボディを持つ関数を使用しました:

template <typename T>
void ignore(T &&)
{ }

void f(int a, int b)
{
  ignore(a);
  ignore(b);
  return;
}

本格的なコンパイラーは関数呼び出しを最適化することを期待しており、警告は表示されません。

38
MadScientist

パラメータ名は省略できます。

int main(int, char *[])
{

    return 0;
}

Mainの場合、パラメーターを完全に省略することもできます。

int main()
{
    // no return implies return 0;
}

C++ 11標準の「§3.6開始と終了」を参照してください。

187
Henrik

そこには <Tuple> inC++ 11、すぐに使用できる std::ignore オブジェクト、これにより書き込みが可能になります(実行時のオーバーヘッドを課すことなく可能性が非常に高い)。

void f(int x)
{
    std::ignore = x;
}
43
Orient

同等のものはありません、いいえ

そのため、同じ古いオプションにこだわっています。パラメーターリストの名前を完全に省略してもよろしいですか?

_int main(int, char**)
_

mainの特定のケースでは、もちろん、パラメーター自体を単に省略できます。

_int main()
_

GCCの__attribute__((unused))など、典型的な実装固有のトリックもあります。

この警告を「無効」にするには、引数を書くのを避け、型を書くだけです。

void function( int, int )
{
}

または、必要に応じてコメントアウトしてください:

void function( int /*a*/, int /*b*/ )
{
}

名前付き引数と名前なし引数を混在させることができます:

void function( int a, int /*b*/ )
{
}

C++ 17では、次のような[[maybe_unused]]属性指定子があります。

void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
{
}
27
Nikko

マクロは理想的ではないかもしれませんが、この特定の目的には適しています。マクロの使用に固執すると思います。

14
Mats Petersson

古い標準的な方法に対して何がありますか?

void f(int a, int b)
{
  (void)a;
  (void)b;
  return;
}
13
jcayzac

Boostヘッダー _<boost/core/ignore_unused.hpp>_ (Boost> = 1.56)は、この目的のために、関数テンプレートboost::ignore_unused()を定義します。

_int fun(int foo, int bar)
{
  boost::ignore_unused(bar);
#ifdef ENABLE_DEBUG_OUTPUT
  if (foo < bar)
    std::cerr << "warning! foo < bar";
#endif

  return foo + 2;
}
_

PS C++ 17には _[[maybe_unused]]_ 属性があり、未使用のエンティティに関する警告を抑制します。

12
manlio

新しいものはありません。

私にとって最適なのは、実装のパラメーター名をコメントアウトすることです。そうすれば、警告を取り除くことができますが、パラメーターが何であるかという概念を保持します(名前が利用可能であるため)。

マクロ(および他のすべてのvoidへのキャストアプローチ)には、マクロを使用した後に実際にパラメーターを使用できるという欠点があります。これにより、コードの保守が難しくなります。

12
Angew

さまざまなデバッグビルドがある場合(たとえば、アサートを有効にしてビルドする場合)に、より適切に制御できるため、マクロを使用するのが大好きです。

#if defined(ENABLE_ASSERTS)
  #define MY_ASSERT(x) assert(x)
#else
  #define MY_ASSERT(x)
#end

#define MY_UNUSED(x)

#if defined(ENABLE_ASSERTS)
  #define MY_USED_FOR_ASSERTS(x) x
#else
  #define MY_USED_FOR_ASSERTS(x) MY_UNUSED(x)
#end

そして次のように使用します:

int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar))
{
  MY_ASSERT(myChar < 12.0f);
  return myInt;
}
0
steeveeet

私は、コードのタイムクリティカルなセグメントに独自の実装をしています。私はしばらくの間、スローダウンのためのタイムクリティカルなコードを調査してきましたが、この実装は、最適化されているタイムクリティカルなコードの約2%を消費することがわかりました。

#define UTILITY_UNUSED(exp) (void)(exp)
#define UTILITY_UNUSED2(e0, e1) UTILITY_UNUSED(e0); UTILITY_UNUSED(e1)
#define ASSERT_EQ(v1, v2) { UTILITY_UNUSED2(v1, v2); } (void)0

タイムクリティカルなコードはASSERT*定義はデバッグ用ですが、リリースでは明らかに切り捨てられましたが、...これはVisual Studio 2015 Update 3

#define UTILITY_UNUSED(exp) (void)(false ? (false ? ((void)(exp)) : (void)0) : (void)0)
#define UTILITY_UNUSED2(e0, e1) (void)(false ? (false ? ((void)(e0), (void)(e1)) : (void)0) : (void)0)

理由はdouble false ?式。最大限の最適化が行われたリリースでは、何らかの理由でコードが少し高速になります。

なぜこれが速いのかわかりませんが(コンパイラ最適化のバグのようです)、少なくともそのコードの場合にはより良い解決策です。

:ここで最も重要なことは、タイムクリティカルなコードの速度が低下することです。withoutは、アサーションまたはリリースで使用されていないマクロです。言い換えると、二重のfalse ? expressionは、驚くべきことにコードの最適化に役立ちます。

0
Andry