扩展编译器以在编译时评估 "complicated" 函数(具有已知输入值),超出 `constexpr` 范围

Extending the compiler to evaluate "complicated" function (with known input values) at compile time, out of `constexpr` reach

请看this example。尝试使用 constexpr 获得编译时评估将是非常困难的,如果不是不可能的话。

但是,调用函数的所有参数在编译时都是已知的。理论上,(存在一些优化属性?),编译器可以暂停解析,用函数创建一个小程序,编译它,运行 它,并得到结果来创建一个 char 常量以用于主程序编译。

我知道问题之一是例如交叉编译:如果编译器可以构建一个可以 运行 在机器上的程序,你只能 运行 来自编译器的程序建造。但这似乎并非无法克服。

毫无疑问:我不是第一个想到它的人。但我试图搜索,但只找到了 constexprtemplate 的东西。将来有没有计划在任何编译器中实现这样的功能?该功能也可以改写为:提供在您的 C++ 源代码中编写 C++ 程序的可能性,编译器可以编译并 运行 根据请求创建常量。

constexprtemplate 是 C++ 中强制编译器在编译时做某事的唯一方法。 在许多情况下,优化器也能够计算出更复杂的函数。 然而,你可能会不经意地离开编译器的“舒适区”,例如通过一些分配 and/or 指针算法。

正如 Marc Glisse 在评论中指出的那样,在您的具体示例中,您使用的是 std::string 而不是本机 char* 并且由于在 class 的实现中完成了魔法,优化器可能会丢失。

也就是说,您可能会欢迎 C++14,它放宽了函数为 constexpr 的要求。 您现在可以声明局部变量、可变对象和基本控制流结构。 您也可以操作原始字符串。

https://isocpp.org/wiki/faq/cpp14-language#extended-constexpr


从更广泛的角度来看,正在进行一项将暂存引入编程语言的研究。 暂存是一种通过显式代码结构对程序进行部分评估的想法,允许在编译时执行甚至最复杂的功能。 从不同角度解决问题的一些示例方法:

请注意,尽管它们都没有尝试在 C++ 中执行此操作。

您基本上想要与标准 C++ 提供的不同的东西。请注意,语言标准并未定义需要哪些优化,但仅定义了大部分优化是合法的。

给出一些一般提示。

如果您在 POSIX(例如 Linux),您还可以在 "runtime" 生成一些 specialized C++ 代码,fork a对其进行编译,并在生成的 "plugin" 上使用动态加载工具(即 dlopen);更具体地说:

  • 具有要生成的 AST C++ 子集的某些模型
  • 使用 -rdynamic -ldl
  • 编译和 link 你的主程序
  • 定义一些关于如何调用插件的约定,例如决定你想要一些 extern "C" int foo(const char*) 函数。
  • 为该 AST 编写一些声明类型的代码
  • 在某个文件中将发出该 AST 的代码编写为 C++ 代码,生成的 C++ 代码应遵循您的插件约定(因此将提供您想要的 int foo(const char*) 函数;避免 name mangling
  • 具体来说,在临时文件中发出C++代码/tmp/temp1234.cc
  • 通过 运行 类似 g++ -O -Wall -fPIC /tmp/temp1234.cc -shared -o /tmp/temp1234.so 的方式将其编译为共享对象,例如用 system(3) 或其他东西
  • /tmp/temp1234.so 上用 RTLD_NOW|RTLD_GLOBAL 调用 dlopen(3);检查失败(否则,使用 dlerror()
  • 使用 foo 外部名称在 dlopen 提供的句柄上调用 dlsym。这给出了一个函数指针,您可以稍后调用它。

在 Linux 上,你可以重复多次(实际上,至少数十万次,看我的 manydl.c example). My GCC MELT 工具正在做这样的事情。

实际上,GCC MELT 用于自定义和扩展 GCC compiler, and you could perhaps even use for your goals, since it enable customization of GCC; so you might add some new attributes or pragmas marking the functions you would want to specialize and code the MELT extensions doing that specialization (you'll need to understand GCC internals, notably Gimple,因此这将花费您一个多星期的时间,而您的 __COMPACT_PRETTY_FUNCTION__ 可以使用您的一些 附加 GCC 内置由你的 MELT 扩展提供。

所以有类似的东西

#define __COMPACT_PRETTY_FUNCTION__ _builtin_compact_pretty_function()

并编写实现新 _builtin_compact_pretty_function 内置编译器的 MELT 扩展。