Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse a static const std::string in compilation time?

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.

like image 875
Mauricio Ruiz Avatar asked Dec 17 '22 21:12

Mauricio Ruiz


2 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.

like image 162
Sebastian Redl Avatar answered Mar 06 '23 15:03

Sebastian Redl


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:

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

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);
}
like image 23
Michael Veksler Avatar answered Mar 06 '23 17:03

Michael Veksler