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標準でより良い解決策はありますか?マクロを取り除くことができますか?
全てに感謝!
そのために空のボディを持つ関数を使用しました:
template <typename T>
void ignore(T &&)
{ }
void f(int a, int b)
{
ignore(a);
ignore(b);
return;
}
本格的なコンパイラーは関数呼び出しを最適化することを期待しており、警告は表示されません。
パラメータ名は省略できます。
int main(int, char *[])
{
return 0;
}
Mainの場合、パラメーターを完全に省略することもできます。
int main()
{
// no return implies return 0;
}
C++ 11標準の「§3.6開始と終了」を参照してください。
そこには <Tuple>
inC++ 11、すぐに使用できる std::ignore
オブジェクト、これにより書き込みが可能になります(実行時のオーバーヘッドを課すことなく可能性が非常に高い)。
void f(int x)
{
std::ignore = x;
}
同等のものはありません、いいえ
そのため、同じ古いオプションにこだわっています。パラメーターリストの名前を完全に省略してもよろしいですか?
_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 )
{
}
マクロは理想的ではないかもしれませんが、この特定の目的には適しています。マクロの使用に固執すると思います。
古い標準的な方法に対して何がありますか?
void f(int a, int b)
{
(void)a;
(void)b;
return;
}
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]]
_ 属性があり、未使用のエンティティに関する警告を抑制します。
新しいものはありません。
私にとって最適なのは、実装のパラメーター名をコメントアウトすることです。そうすれば、警告を取り除くことができますが、パラメーターが何であるかという概念を保持します(名前が利用可能であるため)。
マクロ(および他のすべてのvoidへのキャストアプローチ)には、マクロを使用した後に実際にパラメーターを使用できるという欠点があります。これにより、コードの保守が難しくなります。
さまざまなデバッグビルドがある場合(たとえば、アサートを有効にしてビルドする場合)に、より適切に制御できるため、マクロを使用するのが大好きです。
#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;
}
私は、コードのタイムクリティカルなセグメントに独自の実装をしています。私はしばらくの間、スローダウンのためのタイムクリティカルなコードを調査してきましたが、この実装は、最適化されているタイムクリティカルなコードの約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は、驚くべきことにコードの最適化に役立ちます。