33

私のアプリケーションは、情報をログに記録するために標準出力以外の出力をLog()使用Error()Panic()ますAssert()。うまく整理するために、すべてのデバッグ要素をDebug名前空間で囲みます。

Assert()関数がソース ファイルと行番号も提供する方が理にかなっていますが、これは__LINE__および__FILE__マクロを使用する場合にのみ可能です。ただし、常にこれら 2 つのパラメーターを指定する必要があるのは、非常に不愉快で非効率的です。

だから、これは私のコードがどのように見えるかです:

namespace Debug {
   void Assert (int condition, std::string message, std::string file, int line);
}

Debug私の質問は、名前空間内にこれら 2 つのパラメーターを含むマクロを配置することは可能ですか? このような:

namespace Debug {
   void Assert_ (int condition, std::string message, std::string file, int line);
   #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)
}

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true");

// Output: Assertion failed on line 10 in file test.cpp:
//           Some_condition should be true

これは有効な c++ ですか? そうでない場合、これを機能させる方法はありますか?

4

5 に答える 5

51

#defineプリプロセッサ ディレクティブです。マクロは、コメントを削除することを除けば、何よりも先に (つまり、コンパイルの前に)置き換えられています。したがって、マクロが置き換えられる時点では、コンパイラは名前空間について何も知りません。

他の人が述べているように、あなたの場合は問題ありません。ただし、次のようにして問題が発生する可能性があります。

namespace A
{
 void Assert_ (int condition, std::string message, std::string file, int line)
 {
     std::cout << "A";
 }
   #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)

}
namespace B
{
 void Assert_ (int condition)
 {
     std::cout << "B";
 }
   #define Assert(a,b) Assert_(a)

}

int main(int argc, char *argv[])
{
    A::Assert(0,"asdasd");
    B::Assert(0,"asdasd");
}

したがって、定義が「名前空間内」にあるように見えますが、そうではなく、最後#defineが常に使用されます。この場合、メインのコードが次のように置き換えられるため、コンパイル時エラーが発生します。

A::Assert(0);
B::Assert(0);

それ以外の

A::Assert(0,"asdasd", _FILE_, _LINE_);
B::Assert(0);
于 2012-08-03T07:28:21.513 に答える
2
namespace Debug
{
    void Assert_(int condition, std::string message, std::string file, int line);
    #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)
}

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true"); 

この特定の使用法はまさにあなたが望むことを行いますが、Assert マクロは決して Debug 名前空間の一部ではありません...それはまさにあなたがしたかのようです:

namespace Debug
{
    void Assert_(int condition, std::string message, std::string file, int line);
}

#define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true"); 

Assertここでは、名前空間にあったため置換が機能しませんDebug(それはあなたのコードまたはこのコードになく、プリプロセッサは名前空間が何であるかを知りません) - がAssertマクロの識別子として認識され、置換Assert_が行われるため機能します、その後、適切なコンパイラーがたまたまそこにあることを発見したDebug::Assert_ ので、翻訳単位の後半のどこかに、まったく関係のないコードがあるとします。

my_object.Assert(my_functor);

マクロ置換は、マクロへの引数の数が間違っていることを示すコンパイル時エラーを生成するために引き続き作動します。無関係なコードが代わりにあったとしましょう:

my_object.Assert(my_functor, "some text");

次に、それは次のように置き換えられます。

my_object.Assert_(my_functor, "some text", __FILE__, __LINE__);

(これとは別に、プリプロセッサ マクロ名に小文字を使用しないのが標準的な方法です)。

于 2012-08-03T08:05:35.360 に答える
1

いいえ、プリプロセッサは名前空間をまったく気にしません。実際、プリプロセッサは、少なくとも概念的には、コンパイラが何かを認識する前に実行されます。

私自身は、標準の ASSERT マクロを実行するだけで、ASSERT と呼ばれるものが「適切な名前空間」にないことを期待しています。問題が解決しました。独自の ASSERT を持つライブラリが必要な場合でも、これに対処する方法を決定できます。ただし、私が現在独自の「アサート」で使用している唯一のライブラリは、それを BOOST_ASSERT またはそのようなものと呼んでいます...

于 2012-08-03T07:32:22.433 に答える
0

__PRETTY_FUNCTION __ マクロを試して、関数の引数を含むすべての名前空間を出力できます。

于 2016-11-10T02:03:43.170 に答える
-2

はい、マクロは期待どおりに展開されます。

Debug::Assert (some_condition, "Some_condition should be true");

に置き換えられます

Debug::Assert_(some_condition, "Some_condition should be true", __FILE__, __LINE__)
于 2012-08-03T07:30:32.737 に答える