如何在编译时将文本文件作为字符串包括在内,而不在文本文件中添加c ++ 11字符串文字前缀和后缀

时间:2018-09-21 04:29:19

标签: c++11 metaprogramming

我知道此站点上有许多类似的问题。我真的很喜欢以下链接中提到的解决方案:

https://stackoverflow.com/a/25021520/884553

经过一些修改,您可以在编译时包含文本文件,例如:

constexpr const char* s = 
#include "file.txt"

要使其正常工作,您必须在原始文件中添加字符串文字前缀和后缀,例如

R"(
This is the original content,
and I don't want this file to be modified. but i
 don't know how to do it.
)";

我的问题是:有没有办法使此工作有效但不修改file.txt?

(我知道我可以使用命令行工具进行复制,添加和添加到副本,在编译后删除副本。我正在寻找一种比这更优雅的解决方案。希望不需要其他工具) / p>

这是我尝试过的(但不起作用):

#include <iostream>

int main() {
  constexpr const char* s =
#include "bra.txt"  // R"(
#include "file.txt" //original file without R"( and )";
#include "ket.txt"  // )";
  std::cout << s << "\n";
  return 0;
}

/opt/gcc8/bin/g++ -std=c++1z a.cpp
In file included from a.cpp:5:
bra.txt:1:1: error: unterminated raw string
 R"(
 ^
a.cpp: In function ‘int main()’:
a.cpp:4:27: error: expected primary-expression at end of input
   constexpr const char* s =
                           ^
a.cpp:4:27: error: expected ‘}’ at end of input
a.cpp:3:12: note: to match this ‘{’
 int main() {
            ^

1 个答案:

答案 0 :(得分:2)

不,这不能完成。

有一个提议允许在编译时包含此类资源,称为std::embed

p1040r1建议的动机部分:

动机

  

每个C和C ++程序员(有时)都会尝试将大块非C ++数据#include放入其代码中。当然,#include期望数据的格式为源代码,因此程序会因出现严重的词法分析器错误而失败。因此,早在1995年使用xxd工具,就采用了许多不同的工具和实践来处理此问题。许多行业都需要这样的功能,包括(但不限于):

     
      
  • 金融发展

         
        
    • 表示性能关键算法的系数和数字常数;
    •   
  •   
  • 游戏开发

         
        
    • 在运行时不会更改的资产,例如图标,固定纹理和其他数据

    •   
    • 着色器和脚本代码;

    •   
  •   
  • 嵌入式开发

         
        
    • 以压缩良好的格式存储大块二进制文件(例如固件)

    •   
    • 将数据放置在没有操作系统或文件系统的芯片和系统的内存中;

    •   
  •   
  • 应用程序开发

         
        
    • 代表数据的压缩二进制blob

    •   
    • 非C ++脚本代码,在运行时不会更改;和

    •   
  •   
  • 服务器开发

         
        
    • 在构建时就已知的配置参数,这些参数被引入以设置限制并提供编译时信息以调整某些负载下的性能
    •   
  •   
     

SSL / TLS证书被硬编码到您的可执行文件中(在部署新证书之前需要重建和潜在的授权)。

     

为实现此目标,事实证明这些工具存在不足之处,并且对C ++开发周期的贡献不佳,因为它继续扩大规模以适应更大,更好的低端设备和高性能机器,从而使开发人员陷入困境构建任务并试图掩盖平台之间令人失望的差异。

     

MongoDB非常友好,可以在下面共享其一些代码。其他公司对示例代码进行了匿名处理,或者只是出于羞耻感而没有直接包含它们,以支持他们的工作流程。作者感谢MongoDB的勇气和对std::embed的支持。

     

对于某种形式的#include_string的请求可以追溯到很长一段时间,其中最古老的堆栈溢出问题之一可以追溯到将近10年。甚至在此之前,还有很多邮件列表帖子和论坛帖子,询问如何获取脚本代码和其他不太可能更改为二进制文件的内容。

     

本文提出了<embed>,以使此过程更加高效,可移植且更加简化。这是理想的示例:

#include <embed>

int main (int, char*[]) {
  constexpr std::span<const std::byte> fxaa_binary = std::embed( "fxaa.spirv" );

  // assert this is a SPIRV file, compile-time  
  static_assert( fxaa_binary[0] == 0x03 && fxaa_binary[1] == 0x02
    && fxaa_binary[2] == 0x23 && fxaa_binary[3] == 0x07
    , "given wrong SPIRV data, check rebuild or check the binaries!" )

  auto context = make_vulkan_context();

  // data kept around and made available for binary
  // to use at runtime
  auto fxaa_shader = make_shader( context, fxaa_binary );

  for (;;) {
    // ...
    // and we’re off!
    // ...
  }

  return 0;
}