Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the line number from the call site using __LINE__ or some other method?

Consider this short program that I wrote:

    #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;
    }

It works just fine, and it gives the proper output:

10
add called on line 6
14

However, I'd like for the line number that is printed to be the line at the call site of the program which in this program should be line 12.

So how can I use __LINE__ or some other method to give me the line number from where the function was invoked?

The desired output would be:

10
add called on line 12
14

I would like for it to be generated from the function itself if possible.


-EDIT-

As a note to the reader, I'm open to any and all options but I am limited to C++17 for my current build environment and I'm using Visual Studio.

like image 655
Francis Cugler Avatar asked Mar 02 '23 06:03

Francis Cugler


2 Answers

You can call it like this instead:

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

Output:

10
add called on line 14
14

Furthermore, You can define a macro to skip the third argument:

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

C++ 20 and beyond

With C++20, we are getting std::source_location which contains information about line number, function, file name. If your compiler supports it, you can use that. Example (tested with g++ 9.3.0). You will not need macros anymore:

#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;
}

Output:

10
add<true> called on line 16
14

With source_location you don't have to use macros anymore. It will correctly print the line

like image 190
Waqar Avatar answered Apr 06 '23 17:04

Waqar


If you could compile your code on Linux using some recent GCC (in July 2020, that means GCC 10), you might compile with g++ -g -O -Wall then use Ian Taylor's libbacktrace (like we do in RefPerSys) since that library parses DWARF debug information.

You might either port that library to your operating system and debug info format, or find some equivalent.

Today, a cruder possibility could be to wrap some functions with macros. For example, instead of calling foo() with some void foo(void); you would have

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

Indeed, C++20 should add feature tests and source_location but you might need to wait a few months for a compiler supporting it. Consider compiling a recent GCC from its source code. AFAIK MinGW 64 runs on Windows (so ask permission to use it).

like image 33
Basile Starynkevitch Avatar answered Apr 06 '23 15:04

Basile Starynkevitch