Re: Кому компил-тайма отсыпать?
От: Doom100500 Израиль  
Дата: 27.04.25 06:15
Оценка: +1 :)
Здравствуйте, Shmj, Вы писали:

S>Вот вам парсер-калькулятор строк в компил-тайме, все как вы любите:

  skip
S>
S>// compile_time_calc.hpp — reference implementation of the constexpr calculator
S>// C++20/23, single-header.  Drop it into a project and `#include`.

S>#ifndef COMPILE_TIME_CALC_HPP
S>#define COMPILE_TIME_CALC_HPP

S>#include <string_view>
S>#include <optional>
S>#include <limits>
S>#include <cstddef>
S>#include <type_traits>

S>//---------------------------------------------------------------------
S>// 1.  NTTP-строка как тип
S>//---------------------------------------------------------------------

S>template<char... Cs>
S>struct lit {
S>    static constexpr char str[sizeof...(Cs) + 1]{ Cs..., '\0' };
S>};

S>// пользовательский литерал       "42*(3+1)"_expr  →  объект типа lit<'4','2','*', ...>

S>template<typename CharT, CharT... Cs>
S>consteval auto operator"" _expr() {
S>    static_assert(std::is_same_v<CharT, char>, "_expr supports only narrow char literals");
S>    return lit<Cs...>{};
S>}

S>//---------------------------------------------------------------------
S>// 2.  Проверка переполнения для пяти базовых операций
S>//---------------------------------------------------------------------

S>constexpr unsigned long long MAX = std::numeric_limits<unsigned long long>::max();

S>constexpr std::optional<unsigned long long> add(unsigned long long a, unsigned long long b) {
S>    return (a > MAX - b) ? std::nullopt : std::optional{ a + b };
S>}
S>constexpr std::optional<unsigned long long> sub(unsigned long long a, unsigned long long b) {
S>    return (a < b) ? std::nullopt : std::optional{ a - b };
S>}
S>constexpr std::optional<unsigned long long> mul(unsigned long long a, unsigned long long b) {
S>    return (b != 0 && a > MAX / b) ? std::nullopt : std::optional{ a * b };
S>}
S>constexpr std::optional<unsigned long long> div(unsigned long long a, unsigned long long b) {
S>    return (b == 0) ? std::nullopt : std::optional{ a / b };
S>}
S>constexpr std::optional<unsigned long long> mod(unsigned long long a, unsigned long long b) {
S>    return (b == 0) ? std::nullopt : std::optional{ a % b };
S>}

S>//---------------------------------------------------------------------
S>// 3.  Рекурсивный парсер-оценщик
S>//---------------------------------------------------------------------

S>struct parser {
S>    std::string_view s;
S>    std::size_t pos = 0;

S>    constexpr bool eof() const { return pos >= s.size(); }
S>    constexpr char peek() const { return eof() ? '\0' : s[pos]; }
S>    constexpr void skip_ws() {
S>        while (!eof() && (peek() == ' ' || peek() == '\t' || peek() == '\n')) ++pos;
S>    }
S>    constexpr bool consume(char c) {
S>        skip_ws();
S>        if (peek() == c) { ++pos; return true; }
S>        return false;
S>    }

S>    // number := [0-9]+
S>    constexpr std::optional<unsigned long long> number() {
S>        skip_ws();
S>        if (peek() < '0' || peek() > '9') return std::nullopt;
S>        unsigned long long v = 0;
S>        while (!eof() && peek() >= '0' && peek() <= '9') {
S>            int digit = peek() - '0';
S>            if (auto nv = mul(v, 10)) {
S>                if (auto nv2 = add(*nv, digit)) {
S>                    v = *nv2;
S>                } else return std::nullopt;
S>            } else return std::nullopt;
S>            ++pos;
S>        }
S>        return v;
S>    }

S>    // factor := number | '(' expr ')'
S>    constexpr std::optional<unsigned long long> factor() {
S>        skip_ws();
S>        if (consume('(')) {
S>            auto val = expr();
S>            if (!val || !consume(')')) return std::nullopt;
S>            return val;
S>        }
S>        return number();
S>    }

S>    // term := factor { ('*' | '/' | '%') factor }
S>    constexpr std::optional<unsigned long long> term() {
S>        auto lhs = factor();
S>        if (!lhs) return std::nullopt;
S>        while (true) {
S>            skip_ws();
S>            char op = peek();
S>            if (op != '*' && op != '/' && op != '%') break;
S>            ++pos;
S>            auto rhs = factor();
S>            if (!rhs) return std::nullopt;
S>            switch (op) {
S>            case '*': lhs = mul(*lhs, *rhs); break;
S>            case '/': lhs = div(*lhs, *rhs); break;
S>            case '%': lhs = mod(*lhs, *rhs); break;
S>            }
S>            if (!lhs) return std::nullopt;
S>        }
S>        return lhs;
S>    }

S>    // expr := term { ('+' | '-') term }
S>    constexpr std::optional<unsigned long long> expr() {
S>        auto lhs = term();
S>        if (!lhs) return std::nullopt;
S>        while (true) {
S>            skip_ws();
S>            char op = peek();
S>            if (op != '+' && op != '-') break;
S>            ++pos;
S>            auto rhs = term();
S>            if (!rhs) return std::nullopt;
S>            switch (op) {
S>            case '+': lhs = add(*lhs, *rhs); break;
S>            case '-': lhs = sub(*lhs, *rhs); break;
S>            }
S>            if (!lhs) return std::nullopt;
S>        }
S>        return lhs;
S>    }
S>};

S>//---------------------------------------------------------------------
S>// 4.  Вспомогательный meta-проход: lit<Cs...> → optional<ULL>
S>//---------------------------------------------------------------------

S>template<char... Cs>
S>consteval std::optional<unsigned long long> eval_impl() {
S>    constexpr std::string_view sv{ lit<Cs...>::str, sizeof...(Cs) }; // без NUL
S>    parser p{ sv };
S>    auto val = p.expr();
S>    p.skip_ws();
S>    return (!val || !p.eof()) ? std::nullopt : val;
S>}

S>// превращаем объект lit<...> в мета-информацию

S>template<typename T>
S>struct parsed;                       // общая шаблонная декларация

S>template<char... Cs>
S>struct parsed<lit<Cs...>> {
S>    static constexpr auto opt = eval_impl<Cs...>();
S>    static constexpr bool ok  = opt.has_value();
S>    static constexpr unsigned long long value = *opt; // ОК использовать, только если ok == true
S>};

S>//---------------------------------------------------------------------
S>// 5.  Концепты и основной шаблон calc
S>//---------------------------------------------------------------------

S>template<auto Lit>
S>concept ValidExpr = parsed<decltype(Lit)>::ok;

S>template<auto Lit>
S>requires ValidExpr<Lit>
S>struct calc {
S>    static constexpr unsigned long long value = parsed<decltype(Lit)>::value;
S>    constexpr operator unsigned long long() const { return value; }
S>};

S>//---------------------------------------------------------------------
S>// 6.  Утилита-alias для SFINAE-френдли value-типа
S>//---------------------------------------------------------------------

S>template<auto Lit>
S>using calc_v = std::integral_constant<unsigned long long, calc<Lit>::value>;


S>#endif // COMPILE_TIME_CALC_HPP


S>int main(int argc, const char * argv[]) {
S>    static_assert(calc<"42 * (10 - 8)"_expr>::value == 84);
S>    static_assert(ValidExpr<"((7+5)*3)"_expr>);
S>}

S>


S>int main(int argc, const char * argv[]) {

S> static_assert(calc<"42 * (10 — 8)"_expr>::value == 84);
S> static_assert(ValidExpr<"((7+5)*3)"_expr>);
S>}


Нихрена не понял, зачем всё это? Разве так не компайл таим?

int main(int argc, const char * argv[]) {
    static_assert(42 * (10 - 8)) == 84);

 //а это вообще в компиляторе по умолчанию проверится.
    // static_assert(ValidExpr<"((7+5)*3)"_expr>);
}


S>


Спасибо за внимание
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.