Как можно реализовать std:: эксперимент:: источник-расположение?
Расширения C++ для основ библиотеки, версия 2 ( N4564) представляет тип std::experimental::source_location
,
§ 14.1.2 [refle.src_loc.creation] говорит:
static constexpr source_location current() noexcept;
Возвраты: Когда вызвано вызовом функции (C++14 § 5.2.2), чье постфиксное выражение является (возможно заключенным в скобки) именованием id-выражения
current
, возвращаетsource_location
с определенным значением реализации. Значение должно зависеть от#line
(C++14 § 16.4) таким же образом, как и для__LINE__
а также__FILE__
, Если вызывается каким-либо другим способом, возвращаемое значение не указано.Примечания. Когда инициализатор нестатических данных используется скобка-или-равный инициализатор, любые вызовы
current
должно соответствовать расположению конструктора или агрегатной инициализации, которая инициализирует член.[ Примечание: при использовании в качестве аргумента по умолчанию (C++14 § 8.3.6), значение
source_location
будет место вызоваcurrent
на сайте вызова. - конец примечания ]
Если я правильно понимаю, то эта функция предназначена для использования таким образом.
#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
? Есть ли экспериментальная реализация этой функции, которую можно посмотреть? Я проверил источники SVN для GCC, но пока ничего не нашел.
1 ответ
Реализация этого потребует поддержки от компилятора. Например, с помощью gcc вы можете использовать встроенные функции, такие как
int __builtin_LINE()
Эта функция эквивалентна препроцессору
__LINE__
макрос и возвращает номер строки вызова встроенного. В C++ аргумент по умолчанию для функцииF
, он получает номер строки вызоваF
,const char * __builtin_FUNCTION()
Эта функция эквивалентна препроцессору
__FUNCTION__
макрос и возвращает имя функции, в которой находится вызов встроенной функции.const char * __builtin_FILE()
Эта функция эквивалентна препроцессору
__FILE__
макрос и возвращает имя файла, в котором находится вызов встроенного. В аргументе C++ по умолчанию для функцииF
, он получает имя файла вызоваF
,