8

std::experimental::source_location will probably be added to the C++ standard at some point. I'm wondering if it possible to get the location information into the compile-time realm. Essentially, I want a function that returns different types when called from different source locations. Something like this, although it doesn't compile because the location object isn't constexpr as it's a function argument:

#include <experimental/source_location>

using namespace std::experimental;

constexpr auto line (const source_location& location = source_location::current())
{
  return std::integral_constant<int, location.line()>{};
}

int main()
{
  constexpr auto ll = line();
  std::cout << ll.value << '\n';
}

This doesn't compile, with a message about

expansion of [...] is not a constant expression

regarding the return std::integral_constant<int, location.line()>{} line. What good it is to have the methods of source_location be constexpr if I can't use them?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
levzettelin
  • 2,600
  • 19
  • 32
  • This doesn't have to do with `std::experimental::source_location` at all. The `line` function is `constexpr`, but its arguments are not `constexpr`. Function arguments are never `constexpr`. In C++20, we may have arbitrary types as template arguments, so it's possible the `source_location` could be a template parameter – Justin Oct 24 '18 at 20:46
  • 2
    On further investigation, this is actually an interesting problem. The only way to get the late construction of the `source_location` object is with a defaulted function argument. A defaulted template argument wouldn't work; it's created early, not late. This may be an oversight. `constexpr` function arguments would fix the problem, but that idea isn't seen too favorably at this time – Justin Oct 24 '18 at 20:55

1 Answers1

8

As Justin pointed the issue with your code is that function argument are not constexpr but the problem of using source_location in a constexpr function in a more useful way is mentioned in the constexpr! functions proposal which says:

The "Library Fundamentals v. 2" TS contains a "magic" source_location class get to information similar to the FILE and LINE macros and the func variable (see N4529 for the current draft, and N4129 for some design notes). Unfortunately, because the "value" of a source_location is frozen at the point source_location::current() is invoked, composing code making use of this magic class is tricky: Typically, a function wanting to track its point of invocation has to add a defaulted parameter as follows:

void my_log_function(char const *msg,
                     source_location src_loc
                        = source_location::current()) {
  // ...
}

This idiom ensure that the value of the source_location::current() invocation is sampled where my_log_function is called instead of where it is defined.

Immediate (i.e., constexpr!) functions, however, create a clean separation between the compilation process and the constexpr evaluation process (see also P0992). Thus, we can make source_location::current() an immediate function, and wrap it as needed in other immediate functions: The value produced will correspond to the source location of the "root" immediate function call. For example:

constexpr! src_line() {
  return source_location::current().line();
}

void some_code() {
  std::cout << src_line() << '\n';  // This line number is output.
}

So this is currently an open problem.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740