Как получить номер линии с места звонка с помощью __LINE__ или другим способом? - PullRequest
4 голосов
/ 13 июля 2020

Рассмотрим эту короткую программу, которую я написал:

    #include <iostream>
    
    template<bool Debug = false>
    constexpr int add(const int& a, const int& b) { 
        if (Debug)
            std::cout << __FUNCTION__ << " called on line " << __LINE__ << '\n';
        return (a + b);
    }
    
    int main() {
        std::cout << add(3, 7) << '\n';
        std::cout << add<true>(5, 9) << '\n';
        return 0;
    }

Она отлично работает и дает правильный результат:

10
add called on line 6
14

Однако я бы хотел строчку номер, который печатается как строка в месте вызова программы, которая в этой программе должна быть строкой 12.

Итак, как я могу использовать __LINE__ или какой-либо другой метод, чтобы дать мне номер строки, откуда функция была вызвана?

Желаемый результат будет:

10
add called on line 12
14

Я хотел бы, чтобы он был сгенерирован из самой функции, если это возможно.


-EDIT-

В качестве примечания для читателя, я открыт для любых вариантов, но я ограничен C ++ 17 для моей текущей сборки среды, и я использую Visual Studio.

Ответы [ 2 ]

5 голосов
/ 13 июля 2020

Вместо этого вы можете назвать это так:

template<bool Debug = false>
constexpr int add(const int& a, const int& b, int loc = __LINE__) { 
    if (Debug)
        std::cout << __FUNCTION__ << " called on line " << loc << '\n';
    return (a + b);
}

int main() {
    std::cout << add(3, 7) << '\n';
    std::cout << add<true>(5, 9, __LINE__) << '\n';
    return 0;
}

Вывод:

10
add called on line 14
14

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

#define add_Debug(a, b) add<true>(a,b,__LINE__)

C ++ 20 и выше

С C ++ 20 мы получаем std::source_location, который содержит информацию о номере строки, функции, имени файла. Если ваш компилятор поддерживает это, вы можете использовать это. Пример (проверено с g ++ 9.3.0). Вам больше не понадобятся макросы:

#include <iostream>
#include <experimental/source_location>

using source_location = std::experimental::source_location;

template<bool Debug = false>
constexpr int add(const int& a, const int& b, source_location l = source_location::current()) { 
    if (Debug)
          // this will print 'main' as function name
          //std::cout << l.function_name() << " called on line " << l.line() << //'\n';
        std::cout << source_location::current().function_name() << " called on line " << l.line() << '\n';


    return (a + b);
}

int main()
{
    std::cout << add(3, 7) << '\n';
    std::cout << add<true>(5, 9) << '\n';

    return 0;
}

Вывод:

10
add<true> called on line 16
14

С source_location вам больше не нужно использовать макросы. Он правильно напечатает строку

2 голосов
/ 13 июля 2020

Если бы вы могли скомпилировать свой код на Linux, используя недавний G CC (в июле 2020 года это означает G CC 10 ), вы могли бы скомпилировать с g++ -g -O -Wall, затем используйте libbacktrace Яна Тейлора (как мы это делаем в RefPerSys ), поскольку эта библиотека анализирует DWARF отладочную информацию.

Вы можете либо перенести эту библиотеку в свою операционную систему и в формат отладочной информации, либо найти какой-нибудь эквивалент.

Сегодня более грубой возможностью было бы обернуть некоторые функции макросами. Например, вместо вызова foo() с некоторым void foo(void); у вас будет

extern void foo_at(const char*fileno, int lineno);
#define foo() foo_at(__FILE__,__LINE__);

Действительно, C ++ 20 должен добавить тесты функций и source_location, но вам, возможно, придется подождать несколько месяцев, пока компилятор не поддерживает его. Рассмотрите возможность компиляции недавнего G CC из его исходного кода. AFAIK MinGW 64 работает на Windows (поэтому спросите разрешения на его использование).

...