altebute.hatenablog.com

犬も歩けば規格にあたる

VC++2013で非推奨属性を扱うdeprecated宣言を使う

C++14 には名前やエンティティに非推奨属性を付加するdeprecated attributeと呼ばれる規格が存在する。

[[deprecated]] attribute
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3760.html

が、残念ながら例によって例の如くMicrosoft Visual C++ 2013ではまだ使えない。

その代わり、VC++2013ではdeprecated pragmaと呼ばれるプリプロセッサディレクティブと、deprecated宣言が存在する。

deprecated (C/C++)
http://msdn.microsoft.com/library/c8xdzzhh.aspx

deprecated (C++)
http://msdn.microsoft.com/library/044swk7y.aspx

上記の機能を用いると、C4996ビルドエラーが生成される*1

コンパイラの警告 (レベル 3) C4996 http://msdn.microsoft.com/library/ttcz0bys.aspx

ここで問題になるのは、VC++2013ではC4996は警告ではなくエラー扱いであることである*2MSDNでは、あくまで「警告」としか書かれていない。罠だろうか。
このエラーを警告として扱うためにプリプロセッサディレクティブ#pragma warningを用いる必要がある。

__declspec(deprecated("This is deprecated function."))
void  DeprecatedFunction(){}

int main()
{
    __pragma(warning(push));
    __pragma(warning(3:4996));
    DeprecatedFunction();
    __pragma(warning(pop));
    return 0;
}

__pragma#pragmaを置き換えるマクロである。__pragma(warning(push))で全ての警告の設定をスタックに格納し、その後C4996の警告レベルを3にセットし、非推奨関数の呼び出し後に__pragma(warning(pop))を用いてスタックしておいた警告の設定をポップしている。
マクロの末尾にセミコロンを置いているのは、VSのスマートインデントでインデントがずれないようにするためである。

warning
http://msdn.microsoft.com/library/2c8f766e.aspx

警告レベルには1から4が存在し、大きいほど重要でない警告となる。あまり低くすると警告が表示されなくなってしまうので、今回は3にした。規定値では、Debugビルドでは警告レベル4は抑制され表示されない。

/w、/Wn、/WX、/Wall、/wln、/wdn、/wen、/won (警告レベル)
http://msdn.microsoft.com/library/thxezb7y.aspx

関数呼び出しそのものをマクロ化してしまえば、固定の警告レベルで警告を出すように出来るが、可能な限り自前でのプリプロセッサを用いたプログラミングは避けたいので上記の様なコードになっている。
MSがdeprecated attributeを実装してくれれば、この様な面倒な記述をしなくて済むのだが……

*1:「ビルドエラー」には「コンパイルエラー」も「警告」も含まれる。

*2:MSDNを見る限り、Compiler Error及びCompiler WarningはそれぞれBuild Errorの分類の1つらしい。警告なのかエラーなのかはっきりせず、物凄く紛らわしい。