std::experimental::source_location 是如何实现的?
How could std::experimental::source_location be implemented?
库基础的 C++ 扩展,版本 2(N4564) introduces the type std::experimental::source_location
。
§14.1.2 [reflection.src_loc.creation] 说:
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 a source_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 to current
at the call site. — end note ]
如果我没理解错的话,那么这个功能就是这样使用的。
#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";
}
}
预期输出:
main.cxx:25: error: a > b
如果没有 std::experimental::source_location
,我们可能会使用辅助宏 THROW_WITH_SOURCE_LOCATION
,它在内部使用 __FILE__
和 __LINE__
宏来正确初始化异常对象。
我想知道图书馆如何实现 std::experimental::source_location
。除非我完全忽略了这一点,否则如果没有特殊的编译器支持,这样做是不可能的。但是需要什么样的神奇编译器功能才能使这项工作正常进行呢?它可以与 std::initializer_list
部署的技巧相媲美吗?是否有此功能的任何实验性实现可供查看?我检查了 the SVN sources for GCC 但还没有找到任何东西。
实现这个需要编译器的支持。例如,with gcc, you could possibly use built-ins functions 喜欢
int __builtin_LINE()
This function is the equivalent to the preprocessor __LINE__
macro and returns the line number of the invocation of the built-in. In a C++ default argument for a function F
, it gets the line number of the call to F
.
const char * __builtin_FUNCTION()
This function is the equivalent to the preprocessor __FUNCTION__
macro and returns the function name the invocation of the built-in is in.
const char * __builtin_FILE()
This function is the equivalent to the preprocessor __FILE__
macro and returns the file name the invocation of the built-in is in. In a C++ default argument for a function F
, it gets the file name of the call to F
.
库基础的 C++ 扩展,版本 2(N4564) introduces the type std::experimental::source_location
。
§14.1.2 [reflection.src_loc.creation] 说:
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 ]
如果我没理解错的话,那么这个功能就是这样使用的。
#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";
}
}
预期输出:
main.cxx:25: error: a > b
如果没有 std::experimental::source_location
,我们可能会使用辅助宏 THROW_WITH_SOURCE_LOCATION
,它在内部使用 __FILE__
和 __LINE__
宏来正确初始化异常对象。
我想知道图书馆如何实现 std::experimental::source_location
。除非我完全忽略了这一点,否则如果没有特殊的编译器支持,这样做是不可能的。但是需要什么样的神奇编译器功能才能使这项工作正常进行呢?它可以与 std::initializer_list
部署的技巧相媲美吗?是否有此功能的任何实验性实现可供查看?我检查了 the SVN sources for GCC 但还没有找到任何东西。
实现这个需要编译器的支持。例如,with gcc, you could possibly use built-ins functions 喜欢
int __builtin_LINE()
This function is the equivalent to the preprocessor
__LINE__
macro and returns the line number of the invocation of the built-in. In a C++ default argument for a functionF
, it gets the line number of the call toF
.const char * __builtin_FUNCTION()
This function is the equivalent to the preprocessor
__FUNCTION__
macro and returns the function name the invocation of the built-in is in.const char * __builtin_FILE()
This function is the equivalent to the preprocessor
__FILE__
macro and returns the file name the invocation of the built-in is in. In a C++ default argument for a functionF
, it gets the file name of the call toF
.