【问题标题】:How to parse a static const std::string in compilation time?如何在编译时解析静态 const std::string?
【发布时间】:2019-02-09 04:53:37
【问题描述】:

我的 C++ 代码中有一些带有绑定的 SQL 查询,这些查询是 static const std::string,因为这些查询很复杂,很容易在某些细节上出错。我想在编译时做一些非常基本的检查,例如计算逗号或: 字符的数量。

【问题讨论】:

  • 您可以通过constexpr 函数和元编程来实现这一点
  • 我可以建议两种常用的替代方案,而不是在编译时向后弯腰完成这项工作(大概是因为您害怕这些检查可能对性能产生影响)? 1) 仅针对应用程序的调试版本对这些检查进行条件编译 (#ifndef NDEBUG ...)。您在开发过程中得到检查,对发布性能没有任何影响。 2) 测量、优化、测量。与 SQL 连接/查询相比,某些字符串检查很可能花费很少的、可忽略的时间。您甚至可能性能问题。
  • @DevSolar 我认为早期错误检查是在编译时解析的真正原因,而不是性能。 OP 实际上是这么说的:“我想在编译时做一些非常基本的检查”

标签: c++ string parsing compilation-time


【解决方案1】:

您不能在编译时解析std::string,因为它只能在运行时构造。但是 StackOverflow 上有很好的答案,描述了如何定义和操作编译时字符串:

  1. Compile time string encryption using constexpr
  2. Conveniently Declaring Compile-Time Strings in C++

他们指的是Scott Schurr's str_const,从第29页开始:

class str_const { // constexpr string
private:
  const char* const p_;
  const std::size_t sz_;
public:
  template<std::size_t N>
  constexpr str_const(const char(&a)[N]) : // ctor
    p_(a), sz_(N-1) {}
  constexpr char operator[](std::size_t n) { // []
    return n < sz_ ? p_[n] : throw std::out_of_range("");
  }
  constexpr std::size_t size() { return sz_; } // size()
};

看看Jason Turner's constexpr JSON parser 是如何工作的。它能够在编译时解析整个 JSON 字符串,因此应该可以在编译时解析和验证 SQL。您只需要使用 Scott 的 std_const 或 Jason 的 static_string 即可。

这是一个简单的扩展,使它与std::string_view 一起玩得更好,并有一个编译时substr 方法:

class str_const {
private:
  const char* const p_;
  const std::size_t sz_;
public:
  template<std::size_t N>
  constexpr str_const(const char(&a)[N]) :
    p_(a), sz_(N-1) {}
  constexpr str_const(const std::string_view & sv) :
    p_(sv.begin()), sz_(sv.size()) {}
  constexpr operator std::string_view() const
  { return {p_, sz_}; }

  constexpr char operator[](std::size_t n) const { // []
    return n < sz_ ? p_[n] : throw std::out_of_range("");
  }
  constexpr std::size_t size() const { return sz_; } // size()
  constexpr const char*c_str() const { return p_; }

  constexpr const char*begin() const { return p_; }
  constexpr const char*end() const { return p_ + sz_; }
  constexpr str_const substr(unsigned from, unsigned size) const
  {
    return from+size <= sz_ ? std::string_view{p_ + from, size} : throw std::out_of_range("");
  }
};
std::ostream & operator<<(std::ostream& out, str_const str) {
   return out << std::string_view(str);
}

【讨论】:

    【解决方案2】:

    正如 Sebastian 已经提到的,如果您需要 std::string,则不能。但也许,作为替代方案,您可以执行constexpr auto query = "MY SQL QUERY"; 之类的操作,我不知道您是否可以修改查询的类型。 然后在运行时,query 可以用来构造一个std::string,如果你需要的话。也可以在编译时进行检查。

    缺点当然是在运行时创建std::string时被复制。

    【讨论】:

      【解决方案3】:

      std::string 在编译时不存在。如果你想有这样的行为,你可以将字符串文字与 constexpr 一起使用,如下所示:

      constexpr const char* const var = "string";
      

      要了解更多信息,请查看为此生成的汇编代码:

      #include <string>
      
      int main()
      {
          constexpr const char* const str = "string";
          const std::string test = "test";
      }
      

      使用X86-64 Clang 6.0.0 编译器和0 优化,

      constexpr const char* const str = "string";
      

      生成以下代码:

      subq    $80, %rsp
      movq    $.L.str, -8(%rbp)
      leaq    -48(%rbp), %rax
      
      .L.str:
              .asciz  "string"
      

      对于const std::string test = "test";,生成下面的代码(只是一个sn-p) 所以它调用了std::allocater,它在堆上分配内存,然后构造字符串对象。

              movq    %rax, %rdi
              movq    %rax, -72(%rbp)         # 8-byte Spill
              callq   std::allocator<char>::allocator() [complete object constructor]
              movl    $.L.str.1, %ecx
              movl    %ecx, %esi
              leaq    -40(%rbp), %rdi
              movq    -72(%rbp), %rdx         # 8-byte Reload
              callq   std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)
              jmp     .LBB0_1
      

      【讨论】:

        【解决方案4】:

        你不能。 static const std::string 在编译时不存在。

        constexpr 函数可以使用字符串文字,但std::string 对象不行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-03
          • 1970-01-01
          相关资源
          最近更新 更多