Вопрос по namespaces, macros, c++ – Можно ли разместить макрос в пространстве имен в C ++?

16

Мое приложение использует другой вывод, чем стандартный вывод для регистрации информации, поэтому я написал свой собственныйLog(), Error(), Panic() а такжеAssert() функции. Чтобы организовать вещи хорошо, я вложил все вещи отладки вDebug Пространство имен.

Это будет иметь больше смысла дляAssert() Функция также обеспечивает исходный файл и номер строки, что возможно только с помощью__LINE__ а также__FILE__ макросы. Однако довольно неприятно, неэффективно и т. Д. Всегда нужно указывать эти два параметра.

Вот так будет выглядеть мой код:

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

У меня вопрос, можно ли поместить макрос, который включает эти два параметра внутри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");

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

Это действительный с ++? Если нет, есть ли способ заставить эту работу?

Это будет работать, но макрос не является частью пространства имен. Paul R
@PaulR Другими словами, если я опущуDebug::Макрос все равно будет работать? Tibi
Нет - вам все еще нужен префикс пространства имен (потому что все, что вы делаете, это переводитеAssert вAssert_ в препроцессоре) - проблема в том, что если вы используетеAssert за пределами пространства имен он все равно будет переведен, что, вероятно, не то, что вы хотите. Paul R

Ваш Ответ

5   ответов
0

Да, и ваш макрос будет расширяться до того, что вы ожидаете.

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

будет заменен

Debug::Assert_(some_condition, "Some_condition should be true", __FILE__, __LINE__)
Вы это проверяете?
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"); 

Это конкретное использование будет делать именно то, что вы хотите, ноthe Assert macro is in no way part of the Debug namespace... это так же, как если бы вы сделали:

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__);

(Отдельно это стандартная практика не использовать строчные буквы в именах макросов препроцессора).

Separately, it's standard practice not to use lower case letters in preprocessor macro names, Я знаю, но возьмем Windows API, например. Существует много макросов, которые не соблюдают эту практику, поэтому они вызывают версию другой функции ascii / unicode. Tibi
26

#define это директива препроцессора. Макросы заменяютсяbefore что-нибудь еще, кроме удаления комментариев (что означает, перед компиляцией). Поэтому во время замены макросов компилятор ничего не знает о ваших пространствах имен.

Как утверждают другие люди, в вашем случае все будет хорошо. Однако вот как вы можете получить проблемы:

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");
}

Таким образом, хотя выглядит так, что определения находятся в «пространствах имен», ониnot, и последнее#define всегда будет использоваться, что в этом случае приведет к ошибке во время компиляции, потому что код в main будет заменен на:

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

вместо

A::Assert(0,"asdasd", _FILE_, _LINE_);
B::Assert(0);
@LuchianGrigore - «проблема» находится в заголовке: «Можно ли поместить макрос в пространство имен в c ++?»
@Tibi - путь не использоватьmacros. Используйте константы или встроенные функции, определенные в вашем пространстве имен.
Я понимаю. Есть ли способ сделать эту работу? Tibi
Почему бы это не сработало.Assert будет расширяться доAssert_ с дополнительными 2 параметрами. В чем проблема?
@KirilKirov Ты меня там немного потерял. Как я могу использовать константы и встроенные функции, чтобы получить строку и исходный файл при вызове функции? Tibi
0

Вы можете попробовать макрос __PRETTY_FUNCTION __, чтобы напечатать все пространства имен, включая аргументы функции.

Хотя это может быть ценным советом для решения проблемы, ответ действительно должен продемонстрировать решение. пожалуйстаedit предоставить пример кода, чтобы показать, что вы имеете в виду. В качестве альтернативы, попробуйте написать это как комментарий.
1

Нет, препроцессор вообще не заботится о пространствах имен. Фактически, препроцессор работает, по крайней мере концептуально, до того, как компилятор что-то увидит.

Для себя я просто делаю стандартный макрос ASSERT и ожидаю, что нет «нормального пространства имен» есть что-то под названием ASSERT. Задача решена. Если мне потребуется библиотека с собственным ASSERT, тогда я все еще могу решить, как с этим справиться; тем не менее, единственная библиотека, которую я сейчас использую, со своей собственной "assert" называет это BOOST_ASSERT или что-то в этом роде ...

Похожие вопросы