4

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

4

4 回答 4

5

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

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

于 2018-09-04T08:00:14.547 回答
4

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

  1. 使用 constexpr 编译时间字符串加密
  2. 在 C++ 中方便地声明编译时字符串

他们从第 29 页开始引用Scott Schurr 的 str_const

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 的 constexpr JSON 解析器是如何工作的。它能够在编译时解析整个 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);
}
于 2018-09-04T09:20:04.527 回答
2

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";生成下面的代码(只是一个片段)所以它调用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
于 2018-09-04T08:19:37.287 回答
0

正如塞巴斯蒂安已经提到的,如果你需要,你不能std::string。但也许,作为替代方案,你可以做一些类似constexpr auto query = "MY SQL QUERY";我不知道你是否被允许修改查询类型的事情。然后在运行时,如果需要,query可以用来构造一个。std::string也可以在编译时进行检查。

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

于 2018-09-04T08:21:58.240 回答