13

C++ Extensions for Library Fundamentals,第 2 版( N4564 ) 引入了 type std::experimental::source_location

§ 14.1.2 [reflection.src_loc.creation] 说:

static constexpr source_location current() noexcept;

返回:当被后缀表达式是(可能带括号的)id 表达式命名的函数调用(C++14 § 5.2.2)调用时current,返回source_location具有实现定义值的 a。该值应受(C++14 § 16.4) 以与 for和#line相同的方式影响。如果以其他方式调用,则返回的值是未指定的。__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吗?是否有此功能的实验性实现可供查看?我已经检查了 GCC 的 SVN 源代码,但还没有找到任何东西。

4

1 回答 1

15

实现这一点需要编译器的支持。例如,使用 gcc,您可以使用内置函数,例如

   int __builtin_LINE()

此函数等效于预处理器__LINE__宏,并返回调用内置函数的行号。在函数的 C++ 默认参数中F,它获取调用的行号F

   const char * __builtin_FUNCTION()

此函数等效于预处理器__FUNCTION__宏,并返回调用内置函数的函数名称。

   const char * __builtin_FILE()

此函数等效于预处理器__FILE__宏,并返回调用内置函数所在的文件名。在函数的 C++ 默认参数中F,它获取调用的文件名F

于 2015-12-21T23:23:53.400 回答