我的 C++ 代码中有一些带有绑定的 SQL 查询,这些查询是static const std::string
,因为这些查询很复杂,很容易在某些细节上出错。我想在编译时做一些非常基本的检查,例如计算逗号或:
字符的数量。
4 回答
你不能。Astatic const std::string
在编译时不存在。
字符串文字可以用于constexpr
函数,但不能用于std::string
对象。
您无法std::string
在编译时解析,因为它只能在运行时构造。但是 StackOverflow 上有很好的答案,描述了如何定义和操作编译时字符串:
他们从第 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);
}
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
正如塞巴斯蒂安已经提到的,如果你需要,你不能std::string
。但也许,作为替代方案,你可以做一些类似constexpr auto query = "MY SQL QUERY";
我不知道你是否被允许修改查询类型的事情。然后在运行时,如果需要,query
可以用来构造一个。std::string
也可以在编译时进行检查。
缺点当然是它在创建 std::string 时在运行时被复制。