Как я могу использовать постоянную времени компиляции __LINE__ в строке? - PullRequest
16 голосов
/ 20 апреля 2010

Я могу просто использовать __LINE__ в качестве параметра метода, но я бы хотел использовать его в функции, которая использует строки.

Например, скажите, что у меня есть это:

11    string myTest()
12    {
13     if(!testCondition)
14       return logError("testcondition failed");
15    }

И я хочу, чтобы результат функции был:

"myTest line 14: условие проверки не выполнено"

Как мне написать logError? Должно ли это быть чудовищем макроса?

Ответы [ 8 ]

29 голосов
/ 20 апреля 2010

Зачем тебе это как строка? Что не так с целым числом? Вот два способа написать logError():

#define logError(str) fprintf(stderr, "%s line %d: %s\n", __FILE__, __LINE__, str)

// Or, forward to a more powerful function
#define logError(str) logError2(__FILE__, __LINE__, str)
void logError2(const char *file, int line, const char *str);

Если вам действительно нужна строка в виде строки, вы можете использовать строковый оператор #, но из-за особенностей работы макросов вам нужно будет обернуть ее в два макроса:

#define STRINGIZE(x) STRINGIZE2(x)
#define STRINGIZE2(x) #x
#define LINE_STRING STRINGIZE(__LINE__)

А теперь LINE_STRING - это макрос, который будет расширяться до строки, содержащей номер текущей строки, где бы он ни раскрывался. Если бы у вас был только один уровень макросов (т. Е. Если бы у вас было #define STRINGIZE(x) #x), то вы бы получали буквальную строку "__LINE__" каждый раз, когда ее расширяли, а это не то, что вам нужно.

29 голосов
/ 20 апреля 2010

Для этого нет никакой причины выполнять какую-либо работу во время выполнения:

#include <iostream>

// two macros ensures any macro passed will
// be expanded before being stringified
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)

// test
void print(const char* pStr)
{
    std::cout << pStr << std::endl;
}

int main(void)
{
    // adjacent strings are concatenated
    print("This is on line #" STRINGIZE(__LINE__) ".");
}

Или:

#define STOP_HAMMER_TIME(x) #x
#define STRINGIFICATE(x) STOP_HAMMER_TIME(x)

Если вы крутой человек, как Джеймс.

9 голосов
/ 20 апреля 2010

Его цель - создать макрос (с именем logError ), который будет автоматически включать необходимые символы и выполнять конкатенацию строк в препроцессоре, используя только строковые литералы.

Итак, объединяя пока ответы в основном правильных ответов, давайте напишем макрос:

#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define logError(msg) (__FILE__ " line " STRINGIZE(__LINE__) ": " msg)

Затем вы можете использовать этот макрос где угодно для создания общего кода сообщения об ошибке в строковом литеральном формате во время компиляции.

Примечание: Вы также можете использовать __FUNCTION__ (или эквивалент, он зависит от компилятора) вместо __FILE__, если хотите, чтобы отслеживать имя функции вместо имени файла.

3 голосов
/ 20 апреля 2010

Да, это ужасно. Вам нужна комбинация макросов. Преобразование целого числа в строку является двухэтапным процессом - вот реализация Boost:

#define BOOST_STRINGIZE(X) BOOST_DO_STRINGIZE(X)
#define BOOST_DO_STRINGIZE(X) #X

Теперь вы можете сгенерировать строку:

logError(__FILE__ BOOST_STRINGIZE(__LINE__) "testcondition failed");   
3 голосов
/ 20 апреля 2010

Применяются обычные варианты форматирования числа в строку: Boost lexical_cast, ostringstream, sprintf или snprintf и т. Д.

Вот одна из моих любимых ссылок по теме: http://www.gotw.ca/publications/mill19.htm

1 голос
/ 20 апреля 2010
std::string logError(const char* file, int line, const char* msg)
{
   std::ostringstream os;
   os << file << ' ' << line << ':' << msg;
   return os.str();
}

Использование:

return logError(__FILE__, __LINE__, "my error message");

Вы могли бы сделать макрос для этого, если бы вы были так склонны:

#define LOG_ERROR(x) logError(__FILE__, __LINE__, (x))

И тогда использование будет:

return LOG_ERROR("my error message");
0 голосов
/ 20 апреля 2010

Попробуйте это?

string myTest(const int lineno)
{
  if(!testCondition)
    return logError ("testcondition failed", lineno);
}

void logError (string msg, const int lineno)
{
  clog << "line " << lineno << ": " << msg << endl;
}
0 голосов
/ 20 апреля 2010
sprintf(newStringBuffer, "myTest line %d: testcondition failed\n", __LINE__);

должен делать это в стиле. Я знаю, что есть способы и способы сделать это с помощью строковых библиотек C ++.

Вы также можете использовать strcat () или strncat или любое другое число библиотек C для этого.

cout <<"String" + __LINE__ + " another string" 

тоже будет работать.

...