182

Cプリプロセッサは、C ++コミュニティによって正当に恐れられ、敬遠されています。インライン関数、定数、およびテンプレートは、通常、より安全で優れた代替手段#defineです。

次のマクロ:

#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)  

型安全性よりも決して優れているわけではありません。

inline bool succeeded(int hr) { return hr >= 0; }

しかし、マクロにはその場所があります。プリプロセッサなしでは実行できないマクロの用途をリストしてください。

投票できるように、各ユースケースを別々の回答に入れてください。前処理者なしで回答の1つを達成する方法を知っている場合は、その回答のコメントでその方法を指摘してください。

4

38 に答える 38

129

__FILE__デバッグ関数のラッパーとして、 、 などを自動的に渡すに__LINE__は:

#ifdef ( DEBUG )
#define M_DebugLog( msg )  std::cout << __FILE__ << ":" << __LINE__ << ": " << msg
#else
#define M_DebugLog( msg )
#endif
于 2008-09-18T19:56:26.227 に答える
94

メソッドは常に完全でコンパイル可能なコードでなければなりません。マクロはコード フラグメントである場合があります。したがって、foreach マクロを定義できます。

#define foreach(list, index) for(index = 0; index < list.size(); index++)

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

foreach(cookies, i)
    printf("Cookie: %s", cookies[i]);

C++11 以降、これは範囲ベースの for loop に取って代わられました。

于 2008-09-18T19:54:22.240 に答える
62

ヘッダーファイルガードにはマクロが必要です。

マクロを必要とする他の領域はありますか?多くはありません(もしあれば)。

マクロの恩恵を受ける他の状況はありますか?はい!!!

私がマクロを使用する場所の1つは、非常に反復的なコードです。たとえば、他のインターフェイス(.NET、COM、Pythonなど)で使用するC ++コードをラップする場合、さまざまな種類の例外をキャッチする必要があります。これが私がそれをする方法です:

#define HANDLE_EXCEPTIONS \
catch (::mylib::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e); \
} \
catch (::std::exception& e) { \
    throw gcnew MyDotNetLib::Exception(e, __LINE__, __FILE__); \
} \
catch (...) { \
    throw gcnew MyDotNetLib::UnknownException(__LINE__, __FILE__); \
}

これらのキャッチをすべてのラッパー関数に入れる必要があります。毎回完全なcatchブロックを入力するのではなく、次のように入力します。

void Foo()
{
    try {
        ::mylib::Foo()
    }
    HANDLE_EXCEPTIONS
}

これにより、メンテナンスも容易になります。新しい例外タイプを追加する必要がある場合、追加する必要がある場所は1つだけです。

他にも便利な例があります。その多くには、__FILE__および__LINE__プリプロセッサマクロが含まれています。

とにかく、マクロは正しく使用すると非常に便利です。マクロは悪ではありません-それらの誤用は悪です。

于 2008-09-18T20:02:33.983 に答える
54

多くの場合:

  1. ガードを含める
  2. 条件付きコンパイル
  3. レポート (__LINE__や などの定義済みマクロ__FILE__)
  4. (まれに) 反復コード パターンの複製。
  5. 競合他社のコードで。
于 2008-10-17T16:03:59.657 に答える
50

条件付きコンパイルの内部で、コンパイラ間の違いの問題を克服するには、次のようにします。

#ifdef WE_ARE_ON_WIN32
#define close(parm1)            _close (parm1)
#define rmdir(parm1)            _rmdir (parm1)
#define mkdir(parm1, parm2)     _mkdir (parm1)
#define access(parm1, parm2)    _access(parm1, parm2)
#define create(parm1, parm2)    _creat (parm1, parm2)
#define unlink(parm1)           _unlink(parm1)
#endif
于 2008-09-18T20:00:32.460 に答える
37

式から文字列を作成したい場合、これの最良の例はassert(#xの値をx文字列に変換する) です。

#define ASSERT_THROW(condition) \
if (!(condition)) \
     throw std::exception(#condition " is false");
于 2008-09-18T19:54:05.797 に答える
34

文字列定数は、const char *.

たとえば、文字列リテラルは簡単に連結できます。

#define BASE_HKEY "Software\\Microsoft\\Internet Explorer\\"
// Now we can concat with other literals
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "Settings", &settings);
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "TypedURLs", &URLs);

が使用された場合、const char *実行時に連結を実行するために、ある種の文字列クラスを使用する必要があります。

const char* BaseHkey = "Software\\Microsoft\\Internet Explorer\\";
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "Settings").c_str(), &settings);
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "TypedURLs").c_str(), &URLs);
于 2008-10-22T20:26:21.997 に答える
24

プログラム フロー ( returnbreakおよびcontinue) を変更する場合、関数内のコードは、関数内で実際にインライン化されているコードとは異なる動作をします。

#define ASSERT_RETURN(condition, ret_val) \
if (!(condition)) { \
    assert(false && #condition); \
    return ret_val; }

// should really be in a do { } while(false) but that's another discussion.
于 2008-09-18T19:50:47.303 に答える
20

明らかなインクルードガード

#ifndef MYHEADER_H
#define MYHEADER_H

...

#endif
于 2008-09-18T19:53:01.773 に答える
17

UnitTest++のようなC++のユニットテストフレームワークは、プリプロセッサマクロを中心に展開しています。ユニットテストコードの数行は、手動で入力するのはまったく面白くないクラスの階層に展開されます。UnitTest ++のようなものがなく、プリプロセッサの魔法がなければ、C++の単体テストを効率的に作成する方法がわかりません。

于 2008-09-18T20:04:27.597 に答える
17

ヘッダー ガードのような明白なものを無視するとしましょう。

場合によっては、プリコンパイラでコピー アンド ペーストする必要があるコードを生成したいことがあります。

#define RAISE_ERROR_STL(p_strMessage)                                          \
do                                                                             \
{                                                                              \
   try                                                                         \
   {                                                                           \
      std::tstringstream strBuffer ;                                           \
      strBuffer << p_strMessage ;                                              \
      strMessage = strBuffer.str() ;                                           \
      raiseSomeAlert(__FILE__, __FUNCSIG__, __LINE__, strBuffer.str().c_str()) \
   }                                                                           \
   catch(...){}                                                                \
   {                                                                           \
   }                                                                           \
}                                                                              \
while(false)

これにより、次のようにコーディングできます。

RAISE_ERROR_STL("Hello... The following values " << i << " and " << j << " are wrong") ;

次のようなメッセージを生成できます。

Error Raised:
====================================
File : MyFile.cpp, line 225
Function : MyFunction(int, double)
Message : "Hello... The following values 23 and 12 are wrong"

テンプレートとマクロを組み合わせると、さらに良い結果が得られることに注意してください (つまり、変数名と並べて値を自動的に生成します)。

また、たとえばデバッグ情報を生成するために、一部のコードの __FILE__ や __LINE__ が必要になる場合もあります。以下は、Visual C++ の古典です。

#define WRNG_PRIVATE_STR2(z) #z
#define WRNG_PRIVATE_STR1(x) WRNG_PRIVATE_STR2(x)
#define WRNG __FILE__ "("WRNG_PRIVATE_STR1(__LINE__)") : ------------ : "

次のコードと同様:

#pragma message(WRNG "Hello World")

次のようなメッセージが生成されます。

C:\my_project\my_cpp_file.cpp (225) : ------------ Hello World

また、プロパティの getter と setter を生成するなど、# および ## 連結演算子を使用してコードを生成する必要がある場合もあります (これは非常に限られたケースです)。

また、次のように、関数を介して使用するとコンパイルされないコードを生成する場合もあります。

#define MY_TRY      try{
#define MY_CATCH    } catch(...) {
#define MY_END_TRY  }

として使用できる

MY_TRY
   doSomethingDangerous() ;
MY_CATCH
   tryToRecoverEvenWithoutMeaningfullInfo() ;
   damnThoseMacros() ;
MY_END_TRY

(それでも、この種のコードが正しく使用されているのを見たのは一度だけです)

最後になりましたが、有名なboost::foreach!!!

#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );

    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}

(注:boostホームページからのコードのコピー/貼り付け)

これは(IMHO)よりもはるかに優れていstd::for_eachます。

したがって、マクロは通常のコンパイラ規則の範囲外であるため、常に役立ちます。しかし、ほとんどの場合、それらは適切な C++ に変換されていない C コードの実質的な残骸であることがわかります。

于 2008-09-18T20:13:37.607 に答える
16

通常の関数呼び出しを使用して関数呼び出し引数の短絡を実行することはできません。例えば:

#define andm(a, b) (a) && (b)

bool andf(bool a, bool b) { return a && b; }

andm(x, y) // short circuits the operator so if x is false, y would not be evaluated
andf(x, y) // y will always be evaluated
于 2008-09-18T19:52:39.700 に答える
14

C プリプロセッサを恐れることは、蛍光灯があるからといって白熱電球を恐れるようなものです。はい、前者は {電気 | 電気 | プログラマーの時間} 非効率的です。はい、あなたは彼らによって(文字通り)火傷を負う可能性があります. しかし、適切に対処すれば、彼らは仕事を成し遂げることができます。

組み込みシステムをプログラムする場合、C はアセンブラー以外の唯一のオプションでした。デスクトップで C++ を使用してプログラミングし、小さな組み込みターゲットに切り替えた後、非常に多くの C 機能 (マクロを含む) の「非効率性」について心配するのをやめ、それらから得られる最善かつ安全な使用方法を見つけようとすることを学びます。特徴。

アレクサンダー・ステパノフ さんのコメント

C++ でプログラミングするときは、C の遺産を恥じてはいけませんが、それを十分に活用してください。C++ の唯一の問題、さらには C の唯一の問題は、それら自体が独自のロジックと一致していない場合に発生します。

于 2008-10-17T15:46:44.823 に答える
10

非常に高度で便利なものの中には、プリプロセッサ (マクロ) を使用して構築できるものもありますが、これは、テンプレートを含む C++ の「言語構造」を使用して行うことはできません。

例:

何かを C 識別子と文字列の両方にする

Cで列挙型の変数を文字列として使用する簡単な方法

ブースト プリプロセッサ メタプログラミング

于 2008-10-23T21:49:30.173 に答える
9

__FILE__および__LINE__マクロは、QAインフラストラクチャの自動ログファイルスキャナーとともに、情報が豊富な例外のスロー、キャッチ、およびロギングの診断目的で使用されます。

たとえば、スローマクロOUR_OWN_THROWは、テキストによる説明を含む、その例外の例外タイプとコンストラクターパラメーターで使用される場合があります。このような:

OUR_OWN_THROW(InvalidOperationException, (L"Uninitialized foo!"));

このマクロはもちろんInvalidOperationException、コンストラクターパラメーターとしてdescriptionを使用して例外をスローしますが、スローが発生したファイル名と行番号、およびそのテキストの説明で構成されるメッセージをログファイルに書き込みます。スローされた例外はIDを取得し、これもログに記録されます。例外がコード内のどこかでキャッチされた場合、そのようにマークされ、ログファイルは、特定の例外が処理されたことを示します。したがって、後でログに記録される可能性のあるクラッシュの原因ではない可能性があります。未処理の例外は、自動化されたQAインフラストラクチャによって簡単に検出できます。

于 2008-09-18T20:05:51.697 に答える
8

コードの繰り返し。

boost preprocessor libraryを見てください。これは一種のメタメタプログラミングです。topic->motivation で良い例を見つけることができます。

于 2011-11-06T12:41:18.530 に答える
7

情報を1か所で定義できるようにマクロを使用することもありますが、コードのさまざまな部分でさまざまな方法で使用します。それはほんの少し邪悪です:)

たとえば、「field_list.h」では次のようになります。

/*
 * List of fields, names and values.
 */
FIELD(EXAMPLE1, "first example", 10)
FIELD(EXAMPLE2, "second example", 96)
FIELD(ANOTHER, "more stuff", 32)
...
#undef FIELD

次に、パブリック列挙型の場合、名前だけを使用するように定義できます。

#define FIELD(name, desc, value) FIELD_ ## name,

typedef field_ {

#include "field_list.h"

    FIELD_MAX

} field_en;

また、プライベートinit関数では、すべてのフィールドを使用してテーブルにデータを入力できます。

#define FIELD(name, desc, value) \
    table[FIELD_ ## name].desc = desc; \
    table[FIELD_ ## name].value = value;

#include "field_list.h"
于 2008-09-18T20:50:04.803 に答える
7

一般的な用途の 1 つは、コンパイル環境を検出することです。クロスプラットフォーム開発では、目的のクロスプラットフォーム ライブラリがまだ存在しない場合に、たとえば Linux 用のコード セットと Windows 用の別のコード セットを記述できます。

したがって、大まかな例では、クロスプラットフォームのミューテックスが持つことができます

void lock()
{
    #ifdef WIN32
    EnterCriticalSection(...)
    #endif
    #ifdef POSIX
    pthread_mutex_lock(...)
    #endif
}

関数の場合、型の安全性を明示的に無視したい場合に便利です。ASSERT を実行するための上記および以下の多くの例など。もちろん、多くの C/C++ 機能と同様に、失敗することもありますが、言語はツールを提供し、何をすべきかを決定させてくれます。

于 2008-09-18T19:52:45.630 に答える
6

何かのようなもの

void debugAssert(bool val, const char* file, int lineNumber);
#define assert(x) debugAssert(x,__FILE__,__LINE__);

あなたがちょうど例えば持つことができるように

assert(n == true);

nがfalseの場合は、問題のソースファイル名と行番号をログに出力します。

次のような通常の関数呼び出しを使用する場合

void assert(bool val);

マクロの代わりに取得できるのは、ログに出力されるアサート関数の行番号だけです。これはあまり役に立ちません。

于 2008-09-18T20:03:36.633 に答える
4
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])

現在のスレッドで議論されている「優先」テンプレート ソリューションとは異なり、定数式として使用できます。

char src[23];
int dest[ARRAY_SIZE(src)];
于 2008-09-18T21:41:01.093 に答える
3

コンパイル時にコンパイラ/OS/ハードウェア固有の動作について決定を下す場合。

これにより、コンパイラ/OS/ハードウェア固有の機能へのインターフェイスを作成できます。

#if defined(MY_OS1) && defined(MY_HARDWARE1)
#define   MY_ACTION(a,b,c)      doSothing_OS1HW1(a,b,c);}
#elif define(MY_OS1) && defined(MY_HARDWARE2)
#define   MY_ACTION(a,b,c)      doSomthing_OS1HW2(a,b,c);}
#elif define(MY_SUPER_OS)
          /* On this hardware it is a null operation */
#define   MY_ACTION(a,b,c)
#else
#error  "PLEASE DEFINE MY_ACTION() for this Compiler/OS/HArdware configuration"
#endif
于 2008-09-18T19:55:04.920 に答える
3

#defines を使用して、デバッグおよび単体テストのシナリオに役立てることができます。たとえば、メモリ関数の特別なログ バリアントを作成し、特別な memlog_preinclude.h を作成します。

#define malloc memlog_malloc
#define calloc memlog calloc
#define free memlog_free

以下を使用してコードをコンパイルします。

gcc -Imemlog_preinclude.h ...

memlog.o 内の最終イメージへのリンク。おそらくロギングの目的で、または単体テストの割り当て失敗をシミュレートするために、malloc などを制御します。

于 2008-09-18T21:03:34.973 に答える
2

例外を簡単に定義するためにマクロを使用します。

DEF_EXCEPTION(RessourceNotFound, "Ressource not found")

ここで、DEF_EXCEPTION は

#define DEF_EXCEPTION(A, B) class A : public exception\
  {\
  public:\
    virtual const char* what() const throw()\
    {\
      return B;\
    };\
  }\
于 2011-06-15T21:13:21.000 に答える
2

コンパイラは、インラインへのリクエストを拒否できます。

マクロには常にその場所があります。

私が便利だと思うのは、デバッグ トレース用の #define DEBUG です。問題をデバッグしている間は 1 のままにし (または開発サイクル全体でオンのままにしておくこともできます)、出荷時にオフにすることができます。

于 2008-09-18T19:54:39.617 に答える
2

前回の仕事では、ウィルス スキャナの作業をしていました。デバッグを容易にするために、あちこちにたくさんのログを残しましたが、このような需要の高いアプリでは、関数呼び出しの費用が高すぎます。そこで、この小さなマクロを思いつきました。これにより、顧客のサイトでリリース バージョンのデバッグ ログを有効にすることができます。関数呼び出しのコストはデバッグ フラグをチェックし、何もログに記録せずに戻ります。有効になっている場合は、 、ロギングを行います...マクロは次のように定義されました:

#define dbgmsg(_FORMAT, ...)  if((debugmsg_flag  & 0x00000001) || (debugmsg_flag & 0x80000000))     { log_dbgmsg(_FORMAT, __VA_ARGS__);  }

ログ関数の VA_ARGS のため、これはこのようなマクロの適切なケースでした。

その前に、ユーザーに正しいアクセス権がないことを伝える必要がある高セキュリティ アプリケーションでマクロを使用し、必要なフラグを伝えました。

次のように定義されたマクロ:

#define SECURITY_CHECK(lRequiredSecRoles) if(!DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, true)) return
#define SECURITY_CHECK_QUIET(lRequiredSecRoles) (DoSecurityCheck(lRequiredSecRoles, #lRequiredSecRoles, false))

次に、UI 全体にチェックを振りかけるだけで、実行しようとしたアクションの実行が許可されているロールが、まだそのロールを持っていない場合に通知されます。それらの2つの理由は、ある場所で値を返し、他の場所でvoid関数から戻ることでした...

SECURITY_CHECK(ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR);

LRESULT CAddPerson1::OnWizardNext() 
{
   if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_EMPLOYEE) {
      SECURITY_CHECK(ROLE_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD ) -1;
   } else if(m_Role.GetItemData(m_Role.GetCurSel()) == parent->ROLE_CONTINGENT) {
      SECURITY_CHECK(ROLE_CONTINGENT_WORKER_ADMINISTRATOR | ROLE_BUSINESS_INFORMATION_STEWARD | ROLE_WORKER_ADMINISTRATOR) -1;
   }
...

とにかく、それが私がそれらを使用した方法であり、これがテンプレートでどのように役立つかはわかりません...それ以外は、本当に必要でない限り、それらを避けようとします.

于 2008-09-19T03:52:38.610 に答える
1

VA_ARGSは、これまで間接的にしか言及されていないようです。

ジェネリックC++03コードを記述し、可変数の(ジェネリック)パラメーターが必要な場合は、テンプレートの代わりにマクロを使用できます。

#define CALL_RETURN_WRAPPER(FnType, FName, ...)          \
  if( FnType theFunction = get_op_from_name(FName) ) {   \
    return theFunction(__VA_ARGS__);                     \
  } else {                                               \
    throw invalid_function_name(FName);                  \
  }                                                      \
/**/

注:get_op_from_name一般に、名前のチェック/スローは、仮説関数に組み込むこともできます。これは単なる例です。VA_ARGS呼び出しを取り巻く他の一般的なコードがある可能性があります。

C ++ 11で可変個引数テンプレートを取得したら、テンプレートを使用してこれを「適切に」解決できます。

于 2011-08-16T12:03:32.367 に答える
1

プリプロセッサを使用して、コンパイルされたコードで浮動小数点を使用できない組み込みシステムで使用される浮動小数点値から固定小数点数を計算しました。実数の単位ですべての数学を持ち、固定小数点でそれらについて考える必要がないのは便利です。

例:

// TICKS_PER_UNIT is defined in floating point to allow the conversions to compute during compile-time.
#define TICKS_PER_UNIT  1024.0


// NOTE: The TICKS_PER_x_MS will produce constants in the preprocessor.  The (long) cast will
//       guarantee there are no floating point values in the embedded code and will produce a warning
//       if the constant is larger than the data type being stored to.
//       Adding 0.5 sec to the calculation forces rounding instead of truncation.
#define TICKS_PER_1_MS( ms ) (long)( ( ( ms * TICKS_PER_UNIT ) / 1000 ) + 0.5 )
于 2009-08-18T23:46:43.227 に答える
1

またはオプション#defineを使用して、コンパイラ コマンド ラインで定数を指定できます。これは、プラットフォームごとに定義される定数をメイクファイルで制御できるため、複数のプラットフォーム用に同じソフトウェアをクロスコンパイルする場合に便利です。-D/D

于 2008-09-19T03:44:59.813 に答える
1

おそらく、マクロの最大の使用法は、プラットフォームに依存しない開発です。型の不一致のケースについて考えてみてください。マクロを使用すると、次のようなさまざまなヘッダー ファイルを使用できます。 --WIN_TYPES.H

typedef ...some struct

--POSIX_TYPES.h

typedef ...some another struct

--program.h

#ifdef WIN32
#define TYPES_H "WINTYPES.H"
#else 
#define TYPES_H "POSIX_TYPES.H"
#endif

#include TYPES_H

私の意見では、他の方法で実装するよりもはるかに読みやすいです。

于 2010-04-18T12:37:15.150 に答える
1

構造体の定義、その構造体のバイナリ形式への/からのシリアル化、データベース挿入の実行など、さまざまなことに使用されるフィールドのリストがある場合は、(再帰的に!) プリプロセッサを使用して回避することができます。フィールドリストを繰り返します。

これは確かに恐ろしいことです。しかし、複数の場所でフィールドの長いリストを更新するよりも良い場合がありますか? 私はこの手法を 1 回だけ使用しましたが、その 1 回は非常に役に立ちました。

もちろん、適切なリフレクションを備えた言語では、同じ一般的な考え方が広く使用されています。クラスを調べて、各フィールドを順番に操作するだけです。C プリプロセッサでこれを行うと、壊れやすく、判読しにくく、常に移植できるとは限りません。だから私は少しおびえながらそれについて言及します。とはいえ、ここは…

(編集:これは@Andrew Johnsonが9/18で言ったことに似ていることがわかりました。ただし、同じファイルを再帰的に含めるというアイデアは、アイデアをもう少し進めます。)

// file foo.h, defines class Foo and various members on it without ever repeating the
// list of fields.

#if defined( FIELD_LIST )
   // here's the actual list of fields in the class.  If FIELD_LIST is defined, we're at
   // the 3rd level of inclusion and somebody wants to actually use the field list.  In order
   // to do so, they will have defined the macros STRING and INT before including us.
   STRING( fooString )
   INT( barInt )   
#else // defined( FIELD_LIST )

#if !defined(FOO_H)
#define FOO_H

#define DEFINE_STRUCT
// recursively include this same file to define class Foo
#include "foo.h"
#undef DEFINE_STRUCT

#define DEFINE_CLEAR
// recursively include this same file to define method Foo::clear
#include "foo.h"
#undef DEFINE_CLEAR

// etc ... many more interesting examples like serialization

#else // defined(FOO_H)
// from here on, we know that FOO_H was defined, in other words we're at the second level of
// recursive inclusion, and the file is being used to make some particular
// use of the field list, for example defining the class or a single method of it

#if defined( DEFINE_STRUCT )
#define STRING(a)  std::string a;
#define INT(a)     long a;
   class Foo
   {
      public:
#define FIELD_LIST
// recursively include the same file (for the third time!) to get fields
// This is going to translate into:
//    std::string fooString;
//    int barInt;
#include "foo.h"
#endif

      void clear();
   };
#undef STRING
#undef INT
#endif // defined(DEFINE_STRUCT)


#if defined( DEFINE_ZERO )
#define STRING(a) a = "";
#define INT(a) a = 0;
#define FIELD_LIST
   void Foo::clear()
   {
// recursively include the same file (for the third time!) to get fields.
// This is going to translate into:
//    fooString="";
//    barInt=0;
#include "foo.h"
#undef STRING
#undef int
   }
#endif // defined( DEFINE_ZERO )

// etc...


#endif // end else clause for defined( FOO_H )

#endif // end else clause for defined( FIELD_LIST )
于 2008-10-03T02:16:15.507 に答える
1

さらに別の foreach マクロ。T: 型、c: コンテナー、i: イテレーター

#define foreach(T, c, i) for(T::iterator i=(c).begin(); i!=(c).end(); ++i)
#define foreach_const(T, c, i) for(T::const_iterator i=(c).begin(); i!=(c).end(); ++i)

使用法 (概念を示すものであり、実際のものではありません):

void MultiplyEveryElementInList(std::list<int>& ints, int mul)
{
    foreach(std::list<int>, ints, i)
        (*i) *= mul;
}

int GetSumOfList(const std::list<int>& ints)
{
    int ret = 0;
    foreach_const(std::list<int>, ints, i)
        ret += *i;
    return ret;
}

利用可能なより良い実装: Google "BOOST_FOREACH"

利用可能な良い記事: Conditional Love: FOREACH Redux (Eric Niebler) http://www.artima.com/cppsource/foreach.html

于 2010-02-04T11:33:17.190 に答える
0

このトリックは、関数でエミュレートできないプリプロセッサの巧妙な使用法だと思います。

#define COMMENT COMMENT_SLASH(/)
#define COMMENT_SLASH(s) /##s

#if defined _DEBUG
#define DEBUG_ONLY
#else
#define DEBUG_ONLY COMMENT
#endif

次に、次のように使用できます。

cout <<"Hello, World!" <<endl;
DEBUG_ONLY cout <<"This is outputed only in debug mode" <<endl;

RELEASE_ONLYマクロを定義することもできます。

于 2008-09-18T20:06:30.667 に答える
0

これをインライン関数として実装できますか?

#define my_free(x) do { free(x); x = NULL; } while (0)
于 2008-09-19T02:31:09.150 に答える
0

多くの場合、次のようなコードになります。

int SomeAPICallbackMethod(long a, long b, SomeCrazyClass c, long d, string e, string f, long double yx) { ... }
int AnotherCallback(long a, long b, SomeCrazyClass c, long d, string e, string f, long double yx) { ... }
int YetAnotherCallback(long a, long b, SomeCrazyClass c, long d, string e, string f, long double yx) { ... }

場合によっては、生活を楽にするために以下を使用します。

#define APIARGS long a, long b, SomeCrazyClass c, long d, string e, string f, long double yx
int SomeAPICallbackMethod(APIARGS) { ... } 

変数名を実際に非表示にするという警告が付属していますが、これは大規模なシステムでは問題になる可能性があるため、これは常に正しいことではなく、場合によっては.

于 2008-09-18T19:52:34.100 に答える
0

リソース コンパイラはリソース識別子のみを理解する (つまり、const や enum では機能しない) ため、Visual Studio でリソース識別子用のマクロが必要です。

于 2008-09-18T20:17:08.363 に答える
0

ブール チェックのオーバーヘッドなしで、デバッグ ビルドで追加のログを有効にし、リリース ビルドで無効にすることができます。したがって、代わりに:

void Log::trace(const char *pszMsg) {
    if (!bDebugBuild) {
        return;
    }
    // Do the logging
}

...

log.trace("Inside MyFunction");

あなたが持つことができます:

#ifdef _DEBUG
#define LOG_TRACE log.trace
#else
#define LOG_TRACE void
#endif

...

LOG_TRACE("Inside MyFunction");

_DEBUG が定義されていない場合、コードはまったく生成されません。プログラムの実行速度が向上し、トレース ログのテキストが実行可能ファイルにコンパイルされなくなります。

于 2008-10-17T16:08:53.890 に答える
-1
#define COLUMNS(A,B) [(B) - (A) + 1]

struct 
{
    char firstName COLUMNS(  1,  30);
    char lastName  COLUMNS( 31,  60);
    char address1  COLUMNS( 61,  90);
    char address2  COLUMNS( 91, 120);
    char city      COLUMNS(121, 150);
};
于 2011-05-08T04:12:25.953 に答える