I have some SQL queries with binds in my C++ code, those queries are static const std::string
, because those queries are complex it is very easy to be wrong with some details. I would like to do some very basic checks in compilation time, for example counting the number of commas or :
character.

- 11,148
- 4
- 27
- 40

- 322
- 2
- 10
-
You can achieve that with `constexpr` functions and metaprogramming basically – M. Sol Sep 04 '18 at 08:06
-
Instead of bending over backwards to get this done at compile time (presumably because you are afraid of the impact these checks might have on performance), may I suggest two commonly employed alternatives? 1) Make those checks conditionally-compiled for debug versions of your application only (`#ifndef NDEBUG ...`). You get the checks during development, without any impact on release performance. 2) _Measure, optimize, measure_. Compared with a SQL connect / query, some string checking is most likely taking a tiny, negligible amount of time. You might not even _have_ a performance problem. – DevSolar Sep 04 '18 at 08:29
-
@DevSolar I think early error checking is the real reason to parse at compile time, not performance. The OP actually said so: "I would like to do some very basic checks in compilation time" – Sebastian Redl Sep 04 '18 at 13:19
4 Answers
You can't. A static const std::string
doesn't exist at compile time.
String literals are possible with constexpr
functions, but not std::string
objects.

- 69,373
- 8
- 123
- 157
You can't parse std::string
at compile time, because it can be constructed only at run-time. But there are nice answers at StackOverflow that describes how to define and manipulate compile-time strings:
They refer to of Scott Schurr's str_const starting at page 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()
};
See how Jason Turner's constexpr JSON parser works. It is able to parse a whole JSON string at compile time, so it should be possible to parse and validate SQL at compile time. You just need to use Scott's std_const, or Jason's static_string for that.
Here is a trivial extension that makes it play nicer with std::string_view
, and have a compile-time substr
method:
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);
}

- 8,217
- 1
- 20
- 33
std::string
doesn't exist at compile time. If you want to have such a behavior, you can use the string literals with constexpr as below:
constexpr const char* const var = "string";
To understand more about this, please see the assemble code generated for this:
#include <string>
int main()
{
constexpr const char* const str = "string";
const std::string test = "test";
}
With X86-64 Clang 6.0.0
compiler and with 0
optimizations,
constexpr const char* const str = "string";
generated below code:
subq $80, %rsp
movq $.L.str, -8(%rbp)
leaq -48(%rbp), %rax
.L.str:
.asciz "string"
and for const std::string test = "test";
below code is generated (Just a snippet)
So it calls the std::allocater
which allocates the memory on the heap and then constructs the string object.
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

- 1,239
- 10
- 28
-
if `std::string` is short enough for SSO, can't `static const std::string` still be a compile time object? – bloody Feb 01 '23 at 14:46
As Sebastian already mentioned, you can't if you need std::string
. But maybe, as an alternative, you can do something like constexpr auto query = "MY SQL QUERY";
I don't know if you are allowed to modify the type of the queries.
Then at runtime, query
can be used to construct a std::string
if you need one. Checks at compile time can also be done.
The disadvantage of course is that it is copied at runtime when creating a std::string.

- 139
- 3
- 11