C++ Extensions for Library Fundamentals, Version 2 (N4564) introduces the type std::experimental::source_location
.
§ 14.1.2 [reflection.src_loc.creation] says:
static constexpr source_location current() noexcept;
Returns: When invoked by a function call (C++14 § 5.2.2) whose postfix-expression is a (possibly parenthesized) id-expression naming
current
, returns asource_location
with an implementation-defined value. The value should be affected by#line
(C++14 § 16.4) in the same manner as for__LINE__
and__FILE__
. If invoked in some other way, the value returned is unspecified.Remarks: When a brace-or-equal-initializer is used to initialize a non-static data member, any calls to
current
should correspond to the location of the constructor or aggregate initialization that initializes the member.[ Note: When used as a default argument (C++14 § 8.3.6), the value of the
source_location
will be the location of the call tocurrent
at the call site. — end note ]
If I understand correctly, then the feature is intended to be used like this.
#include <experimental/source_location> // I don't actually have this header
#include <iostream>
#include <string>
#include <utility>
struct my_exception
{
std::string message {};
std::experimental::source_location location {};
my_exception(std::string msg,
std::experimental::source_location loc = std::experimental::source_location::current()) :
message {std::move(msg)},
location {std::move(loc)}
{
}
};
int
do_stuff(const int a, const int b)
{
if (a > b)
throw my_exception {"a > b"}; // line 25 of file main.cxx
return b - a;
}
int
main()
{
try
{
std::cout << do_stuff(2, 1) << "\n";
}
catch (const my_exception& e)
{
std::cerr << e.location.file_name() << ":" << e.location.line() << ": "
<< "error: " << e.message << "\n";
}
}
Expected output:
main.cxx:25: error: a > b
Without std::experimental::source_location
, we might have used a helper macro THROW_WITH_SOURCE_LOCATION
that internally makes use of the __FILE__
and __LINE__
macros to initialize the exception object properly.
I was wondering how a library could implement std::experimental::source_location
. Unless I'm completely missing the point, doing so is not possible without special compiler support. But what kind of magic compiler features would be needed to make this work? Would it be comparable to the trick deployed for std::initializer_list
? Is there any experimental implementation of this feature available to look at? I have checked the SVN sources for GCC but didn't find anything yet.
std::type_info
– Anglicismtypeid
can be implemented as a fairly straight-forward function. For non-polymorphic types, the compiler already knows the answer can can directly insert a string literal, for polymorphic types, it has to generate simple code to follow thevptr
at run-time. I don't see howsource_location
would be equally simple to implement. But if you know, then that's exactly the kind of answer I'm looking for. – Daniais_class/enum/union
. – Interfertile__FILE__
and__LINE__
work. Allstd::source_location
will do is formalise the relationship with user code. Much as the compiler/standard library does forstd::initializer_list
(another 'magic' class) – Anglicismstd::cout << __LINE__ << std::endl
work? Remember that after expanding preprocessor directives (such as #include) all the actual line numbers has shifted, and yet our code reports the ones we expect. There is a loose but intimate relationship between the preprocessor and the compiler stages. – Anglicism