std::experimental::source_location at compile time
Asked Answered
H

1

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?

Hybris answered 24/10, 2018 at 20:39 Comment(2)
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 parameterSalmonella
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 timeSalmonella
D
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.

Defibrillator answered 24/10, 2018 at 21:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.