7

最近、Scott Meyers による「Effective C++ Second Edition」を読んで、C++ のベスト プラクティスを改善しています。彼がリストした項目の 1 つは、C++ プログラマーがプリプロセッサ マクロを避け、「コンパイラを優先する」ことを奨励しています。彼は、#include と #ifdef/#ifndef を除いて、C++ でマクロを使用する理由はほとんどないとまで言いました。

次のマクロを実行できるため、彼の推論に同意します

#define min(a,b) ((a) < (b) ? (a) : (b))

次の C++ 言語機能を使用

template<class T>
inline const T & min(const T & a, const T & b) {
    return a < b ? a : b;
}

where inline は、関数呼び出しを削除し、オーバーロードまたは組み込み > 演算子を持つ複数のデータ型を処理できるインライン コードとテンプレートを挿入するオプションをコンパイラに提供します。

EDIT-- a と b のデータ型が異なる場合、このテンプレート宣言は指定されたマクロと完全には一致しません。例については、ピートのコメントを参照してください。

ただし、デバッグ ログにマクロを使用することが C++ で有効であるかどうかを知りたいと思っています。以下に示す方法が適切でない場合、誰かが別の方法を提案してくれますか?

私は昨年、Objective-C でコーディングを行っており、私のお気に入りの 2D エンジン (cocos2d) の 1 つはマクロを使用してログ ステートメントを作成していました。マクロは次のとおりです。

/*


* if COCOS2D_DEBUG is not defined, or if it is 0 then
 *  all CCLOGXXX macros will be disabled
 *
 * if COCOS2D_DEBUG==1 then:
 *      CCLOG() will be enabled
 *      CCLOGERROR() will be enabled
 *      CCLOGINFO() will be disabled
 *
 * if COCOS2D_DEBUG==2 or higher then:
 *      CCLOG() will be enabled
 *      CCLOGERROR() will be enabled
 *      CCLOGINFO() will be enabled
 */


#define __CCLOGWITHFUNCTION(s, ...) \
NSLog(@"%s : %@",__FUNCTION__,[NSString stringWithFormat:(s), ##__VA_ARGS__])

#define __CCLOG(s, ...) \
NSLog(@"%@",[NSString stringWithFormat:(s), ##__VA_ARGS__])


#if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0
#define CCLOG(...) do {} while (0)
#define CCLOGWARN(...) do {} while (0)
#define CCLOGINFO(...) do {} while (0)

#elif COCOS2D_DEBUG == 1
#define CCLOG(...) __CCLOG(__VA_ARGS__)
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
#define CCLOGINFO(...) do {} while (0)

#elif COCOS2D_DEBUG > 1
#define CCLOG(...) __CCLOG(__VA_ARGS__)
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
#define CCLOGINFO(...) __CCLOG(__VA_ARGS__)
#endif // COCOS2D_DEBUG

このマクロは、私の C++ プログラムに組み込みたい素晴らしいユーティリティを提供します。便利なログ ステートメントを書くのは、次のように簡単です。

CCLOG(@"Error in x due to y");

さらに優れているのは、COCOS2D_DEBUG が 0 に設定されている場合、これらのステートメントが日の目を見ないことです。ロギング ステートメントを使用する必要があるかどうかを確認するために条件ステートメントをチェックするためのオーバーヘッドはありません。開発から本番へ移行する際に便利です。これと同じ効果を C++ で再現するにはどうすればよいでしょうか?

このタイプのマクロは C++ プログラムに属しますか? これを行うためのより良い、よりC++の方法はありますか?

4

2 に答える 2

2

マクロを使用する「正しい」ことと、マクロの不適切な使用があります。関数が動作する場所でマクロを使用するのは悪い考えです。私の本では、関数が同じことをしないマクロを使用することは完全に良いことです。

私はよく次のような構成を使用します。

#defien my_assert(x) do { if (!x) assert_failed(x, #x, __FILE__, __LINE__); } while(0)

template<typename T> 
void assert_failed(T x, const char *x_str, const char *file, int line)
{
   std::cerr << "Assertion failed: " << x_str << "(" << x << ") at " << file << ":" << line << std::endl;
   std::terminate();
}

文字列化「演算子」を使用した別のトリックは、次のようなものです。

enum E
{
   a, 
   b, 
   c,
   d
 };

 struct enum_string
 {
    E v;
    const char *str;
 };

 #define TO_STR(x) { x, #x }

 enum_string enum_to_str[] = 
 {
    TO_STR(a),
    TO_STR(b),
    TO_STR(c),
    TO_STR(d),
  };

繰り返しのものをかなり節約します...

はい、場合によっては便利です。

于 2013-08-04T22:24:04.310 に答える