Как можно реализовать 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,

Другие вопросы по тегам