Как разобрать статический const std :: string во время компиляции? - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть несколько SQL-запросов со связями в моем коде C ++, эти запросы static const std::string, потому что эти запросы сложные, очень легко ошибиться с некоторыми деталями. Я хотел бы сделать некоторые очень простые проверки во время компиляции, например, подсчет количества запятых или : символа.

Ответы [ 4 ]

0 голосов
/ 04 сентября 2018

Вы не можете проанализировать std::string во время компиляции, потому что он может быть создан только во время выполнения. Но в StackOverflow есть хорошие ответы, которые описывают, как определять и обрабатывать строки времени компиляции:

  1. Шифрование строки времени компиляции с использованием constexpr .
  2. Удобное объявление строк времени компиляции в C ++

Они относятся к 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()
};

Посмотрите, как работает JSON-синтаксический анализатор JSON Turner . Он способен анализировать всю строку JSON во время компиляции, поэтому должна быть возможность анализировать и проверять SQL во время компиляции. Для этого вам просто нужно использовать std_const Скотта или 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);
}
0 голосов
/ 04 сентября 2018

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
0 голосов
/ 04 сентября 2018

Как уже говорил Себастьян, вы не можете, если вам нужно std::string. Но, возможно, в качестве альтернативы, вы можете сделать что-то вроде constexpr auto query = "MY SQL QUERY"; Я не знаю, разрешено ли вам изменять тип запросов. Затем во время выполнения, query может быть использовано для создания std::string, если он вам нужен. Проверки во время компиляции также могут быть сделаны.

Недостатком, конечно, является то, что он копируется во время выполнения при создании std :: string.

0 голосов
/ 04 сентября 2018

Вы не можете. static const std::string не существует во время компиляции.

Строковые литералы возможны с constexpr функциями, но не std::string объектами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...