自学内容网 自学内容网

C/C++自定义std::format格式化

C++

#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <iomanip>

template <class T0, class T1, class = void>
struct _has_stream_bit_shl : std::false_type {};

template <class T0, class T1>
struct _has_stream_bit_shl<T0, T1, std::void_t<decltype(
    std::declval<T0>() << std::declval<T1>()
    )>> : std::true_type {};

template <class T, class = void>
struct _has_range_begin_end : std::false_type {};

template <class T>
struct _has_range_begin_end<T, std::void_t<decltype(
    std::begin(std::declval<T>()) != std::end(std::declval<T>())
    )>> : std::true_type {};

template <class T, class = void>
struct _has_tuple_size : std::false_type {};

template <class T>
struct _has_tuple_size<T, std::void_t<decltype(
    std::tuple_size<T>::value
    )>> : std::true_type {};

struct _to_stream_impl {
    template <class Os, class T, std::size_t ...Is>
    static void _helper_tuple_to_stream(Os& os, T const& t, std::string_view fms, std::index_sequence<Is...>) {
        os << '(';
        (to_stream(os, std::get<0>(t), fms), ..., (os << ' ', to_stream(os, std::get<Is + 1>(t), fms)));
        os << ')';
    }

    template <class Os, class T, std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value
        && (std::tuple_size<T>::value >= 1), int> = 0>
    static void to_stream(Os& os, T const& t, std::string_view fms) {
        return _helper_tuple_to_stream(os, t, fms, std::make_index_sequence<std::tuple_size_v<T> -1>{});
    }

    template <class Os, class T>
    static auto to_stream(Os& os, T const& t, std::string_view fms) -> decltype((std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value && !_has_range_begin_end<T>::value, void>)(std::declval<T&>()[0], std::declval<T&>().length())) {
        os << "[glm: ";
        for (int i = 0; i < t.length(); ++i) {
            to_stream(os, t[i], fms);
            os << ", ";
        }
        os << "]";
    }

    template <class Os, class T, std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value
        && (std::tuple_size<T>::value == 0), int> = 0>
    static void to_stream(Os& os, T const& t, std::string_view fms) {
        os << "()";
    }

    template <class Os, class T, std::enable_if_t<!_has_stream_bit_shl<Os&, T const&>::value
        && !_has_tuple_size<T>::value&& _has_range_begin_end<T>::value, int> = 0>
    static void to_stream(Os& os, T const& t, std::string_view fms) {
        auto it = std::begin(t);
        auto eit = std::end(t);
        os << '[';
        if (it != eit) {
            to_stream(os, *it, fms);
            ++it;
            for (; it != eit; ++it) {
                os << ' ';
                to_stream(os, *it, fms);
            }
        }
        os << ']';
    }

    template <class Os, class T, std::enable_if_t<_has_stream_bit_shl<Os&, T const&>::value && !std::is_enum<T>::value, int> = 0>
    static void to_stream(Os& os, T const& t, std::string_view fms) {
        auto flgs = os.flags();
        if (fms.size() != 0) {
            if (fms.size() != 0 && fms[0] == '-') {
                fms = fms.substr(1);
                os << std::right;
            }
            if (fms.size() != 0 && fms[0] == '0') {
                fms = fms.substr(1);
                os << std::setfill('0');
            }
            {
                int tmp = 0;
                while (fms.size() != 0 && '0' <= fms[0] && '9' >= fms[0]) {
                    tmp *= 10;
                    tmp += fms[0] - '0';
                    fms = fms.substr(1);
                }
                if (tmp != 0)
                    os << std::setw(tmp);
            }
            if (fms.size() != 0 && fms[0] == '.') {
                fms = fms.substr(1);
                int tmp = 0;
                while (fms.size() != 0 && '0' <= fms[0] && '9' >= fms[0]) {
                    tmp *= 10;
                    tmp += fms[0] - '0';
                    fms = fms.substr(1);
                }
                os << std::setprecision(tmp);
            }
            if (fms.size() != 0) {
                switch (fms[0]) {
                case 'x': os << std::hex; break;
                case 'd': os << std::dec; break;
                case 'o': os << std::oct; break;
                };
            }
        }
        os << t;
        os.flags(flgs);
    }

    template <class Os, class T, std::enable_if_t<std::is_enum<T>::value
        && _has_stream_bit_shl<Os&, typename std::underlying_type<T>::type const&>::value, int> = 0>
    static void to_stream(Os& os, T const& t, std::string_view fms) {
        os << std::underlying_type_t<T>{t};
    }
};



template <class Os, class T>
void to_stream(Os& os, T const& t, std::string_view fms) {
    _to_stream_impl::to_stream(os, t, fms);
}

template <class T>
std::string to_string(T const& t, std::string_view fms) {
    std::ostringstream ss;
    to_stream(ss, t, fms);
    return ss.str();
}

template <class T>
std::string to_string(T const& t) {
    if constexpr (std::is_convertible_v<T, std::string>) {
        return t;
    }
    else {
        std::ostringstream ss;
        to_stream(ss, t, {});
        return ss.str();
    }
}



template <int curr, class Os, class It, class ...Args>
bool __format(Os& os, It fb, It fe, std::tuple<Args const &...> const& args) {
    if constexpr (curr >= sizeof...(Args)) {
        if (fb != fe)
            os << std::string_view(fb, fe - fb);
        return curr > sizeof...(Args);
    }
    else {
        if (fb == fe) return false;
        auto ib = std::find(fb, fe, '{');
        if (ib == fe) return false;
        os << std::string_view(fb, ib - fb);
        ++ib;
        auto ie = std::find(ib, fe, '}');
        if (ie == fe) return false;
        ++ie;
        auto fms = std::string_view(ib, ie - ib);
        if (auto i = fms.find(':'); i != std::string_view::npos) {
            fms = fms.substr(i + 1);
        }
        to_stream(os, std::get<curr>(args), fms);
        return __format<curr + 1>(os, ie, fe, args);
    }
}

template <class Os, class ...Args>
bool format_to(Os& os, std::string_view fmt, Args const &...args) {
    return __format<0>(os, fmt.data(), fmt.data() + fmt.size(), std::tuple<Args const &...>(args...));
}

template <class ...Args>
std::string format(std::string_view fmt, Args const &...args) {
    std::stringstream ss;
    format_to(ss, fmt, args...);
    return ss.str();
}


void test() {
    std::cout << format("add({}+{})={}\n", 1, 2, 3);
}
C
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <stdarg.h>
#include <string>

template <class ...Ts>
std::string cformat(const char *fmt, Ts &&...ts) {
    int n = snprintf(nullptr, 0, fmt, std::forward<Ts>(ts)...);
    if (n < 0) return {};
    std::string res;
    res.resize(n + 2);
    n = snprintf(res.data(), n + 1, fmt, std::forward<Ts>(ts)...);
    res.resize(n);
    return res;
}

 输出: add(1+2)=3


创作不易,小小的支持一下吧!


原文地址:https://blog.csdn.net/qq_30220519/article/details/140332972

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!