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

2

5

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.

Tryst answered 13/7, 2020 at 5:39 Comment(0)
T
6

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

Tricuspid answered 13/7, 2020 at 5:49 Comment(13)
Not exactly what I was asking for. The function call itself happens at line 12 in the code within the main function. That's the line number that I'm after.Tryst
I am adding more, bear with me :)Tricuspid
This should work... however, having to add that into every function... ehhTryst
It's for debug - unit testing and writing to log files though...Tryst
I hear that C++20 has a new proposed feature... can't wait to be able to start using it!Tryst
Hmm maybe add it into the template arguments instead of the function itself...Tryst
I tried using it as a template argument, setting the template argument as a default to __LINE__ works, however, when I try to use __LINE__ as the second parameter when instantiating the template, it does fail to compile because the __LINE__ macro isn't considered a compile-time constant expression.Tryst
It does work, but the line information you will get will be incorrect unless you explicitly pass __LINE__ like add<true, __LINE__>(5, 9). With source_location, this is not an issue. You can just use it as a function parameter and it will print information of line which called the functionTricuspid
I tried doing that add<true,__LINE__>(5,9) but it was failing to compile for Visual Studio...Tryst
It's compiling for all compilers for me, see: godbolt.org/z/T91s5sTricuspid
Okay, I changed Compiler Explorer's settings to match my environment: x64 MSVC 19.24 and changed it to c++17. It compiled there fine. In Visual Studio 2017 when I compile it in Debug mode it is generating: C2672 and C2975 compile errors. However, when I switch to release mode, it compiles, builds, runs, and produces the correct output... Curious, I wonder if this is a Visual Studio Bug...Tryst
Could be a bug in MSVC. Cause there are no C++17 only features in that template function.Tricuspid
I just asked another question in regards to it being a potential bug! https://mcmap.net/q/642284/-why-does-this-code-using-__line__-compile-under-msvc-in-release-mode-but-not-in-debug-mode/1757805 However, I got a downvote from it already...Tryst
T
2

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).

Thromboplastin answered 13/7, 2020 at 6:14 Comment(1)
Yeah, but that's kind of going backward towards C programming, I'm trying to push the limits of C++ and move forward!Tryst

© 2022 - 2025 — McMap. All rights reserved.