Расширения 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__
, Если вызывается каким-либо другим способом, возвращаемое значение не указано.Примечания: Когда скобки или равно-инициализатор используется для инициализации нестатического члена данных, любых вызовов
[ Замечания: При использовании в качестве аргумента по умолчанию (C ++ 14 §8.3.6), значениеcurrent
должно соответствовать расположению конструктора или агрегатной инициализации, которая инициализирует член.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 но пока ничего не нашел.
Реализация этого потребует поддержки от компилятора. Например, с gcc, вы могли бы использовать встроенные функции лайк
int __builtin_LINE()
Эта функция эквивалентна препроцессору
__LINE__
макрос и возвращает номер строки вызова встроенного. В C ++ аргумент по умолчанию для функцииF
, он получает номер строки вызоваF
,const char * __builtin_FUNCTION()
Эта функция эквивалентна препроцессору
__FUNCTION__
макрос и возвращает имя функции, в которой находится вызов встроенной функции.const char * __builtin_FILE()
Эта функция эквивалентна препроцессору
__FILE__
макрос и возвращает имя файла, в котором находится вызов встроенного. В аргументе C ++ по умолчанию для функцииF
, он получает имя файла вызоваF
,
Других решений пока нет …