4

I have a templated function called from multiple other functions that needs to log the name of the function from which it was called. Ideally, I want to do something like the following:

template <typename T, const char* CALLER>
void foo(const T& arg) {
    // ...
}

However, this does not compile, of course, as CALLER is an invalid template parameter. Of course, I could simply modify the signature of foo to also take in a string (the caller's name) to achieve this.

Question: Is there a preferred C++ idiomatic way to achieve this sort of thing?

Ryan
  • 7,621
  • 5
  • 18
  • 31
  • 1
    You're looking for [`__func__`](https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html), but you may have to resort to macros to get it automatically passed at every callsite. – zwol Apr 10 '17 at 20:25
  • Thanks, @zwol. I was actually already aware of using `__foo__` to get the function name from the calling context. I'm looking for an idiomatic way of passing this into `foo` (as defined above), though. – Ryan Apr 10 '17 at 20:32
  • Unless you need it at compile-time, a simple `string_view` would work best until we get source code information capture. – chris Apr 10 '17 at 20:33
  • 2
    http://en.cppreference.com/w/cpp/experimental/source_location might be interesting too. – Jarod42 Apr 10 '17 at 20:33
  • @Ryan I'm afraid I can't help you with that part (which is why I'm not posting an answer). – zwol Apr 10 '17 at 20:35
  • This is one of the few cases where a macro really is the idiomatic way to do this; Steve's answer is quite good. The main thing to keep in mind is to implement everything you possibly can as a function; keep passing the function name down as a string literal. Only at the very top level, define a user-facing macro. In other words: it's ok to use a macro for this but you should still minimize it. – Nir Friedman Apr 10 '17 at 21:09
  • An alternative btw is to use something like lib backtrace, in conjunction with addr2line or something similar, to get a full backtrace, without using macros or `__func__` at all. This gives you more information but it's quite slow, and far more work to implement. – Nir Friedman Apr 10 '17 at 21:11

1 Answers1

3

Unfortunately you can't use string literals as template arguments

Because string literals are objects with internal linkage (two string literals with the same value but in different modules are different objects), you can't use them as template arguments either

As such you'll likely want to pass it as an argument to your function, eg:

template<typename T>
void foo(T t, const char* func)
{
    std::cout << func << ": " << t << '\n';
}

That then passes the responsibility of calling foo with a valid const char* onto the caller

void bar()
{
    foo(1, __func__); // callers responsibility to pass __func__
}

If this is a burden, you can wrap foo in a macro which will pass __func__ for you.

#define CALL_FOO(x) foo(x, __func__)

void bar()
{
    CALL_FOO(1);      // use the macro to pass __func__
}
Community
  • 1
  • 1
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213