| | #include <algorithm>
#include <iostream>
#include <string>
#include <string_view>
#include <type_traits>
#include <sstream>
namespace fmtlib
{
template<typename T, typename CharT = char>
struct formatter;
template<typename CharT, typename T>
[[nodiscard]]
formatter<T, CharT>
make_formatter(const T &);
template<typename CharT, typename T>
CharT *
format(CharT * dest, T && value)
{
return make_formatter<CharT>(value).format(dest, value);
}
template<>
struct formatter<std::string_view, char>
{
char *
format(char * dest, const std::string_view & v)
{
*(dest++) = '"';
std::copy(v.begin(), v.end(), dest);
dest += v.size();
*(dest++) = '"';
return dest;
}
};
template<>
struct formatter<std::string, char>
: public formatter<std::string_view, char>
{
char *
format(char * dest, const std::string & v)
{
return formatter<std::string_view, char>::format(
dest, std::string_view{v});
}
};
template<>
struct formatter<char, char>
{
char *
format(char * dest, const char v)
{
*(dest++) = v;
return dest;
}
};
template<typename T>
struct formatter<T, std::enable_if_t<std::is_arithmetic_v<T>, char>>
{
char *
format(char * dest, const T & v)
{
std::ostringstream ss;
ss << v;
const auto sv = ss.str();
std::copy(sv.begin(), sv.end(), dest);
dest += sv.size();
return dest;
}
};
template<typename CharT, typename T>
[[nodiscard]]
formatter<T, CharT>
make_formatter(const T &)
{
return {};
}
} /* namespace fmtlib */
namespace one
{
template<typename T>
struct point
{
T x;
T y;
};
} /* namespace one */
template<typename T>
struct fmtlib::formatter<one::point<T>, char>
{
char *
format(char * dest, const one::point<T> & v)
{
dest = fmtlib::format(dest, '{');
dest = fmtlib::format(dest, v.x);
dest = fmtlib::format(dest, ',');
dest = fmtlib::format(dest, v.y);
dest = fmtlib::format(dest, '}');
return dest;
}
};
namespace two
{
template<typename T, typename Tag>
struct value_holder
{
T v;
};
template<typename T, typename Tag, typename CharT>
struct value_holder_formatter
{
CharT *
format(CharT * dest, const value_holder<T, Tag> & v)
{
return fmtlib::formatter<T, CharT>{}.format(dest, v.v);
}
};
template<typename CharT, typename T, typename Tag>
value_holder_formatter<T, Tag, CharT>
make_formatter(const value_holder<T, Tag> &)
{
return {};
}
} /* namespace two */
int
main()
{
using namespace std::string_literals;
using namespace std::string_view_literals;
char buf[1024];
struct tag_1 {};
struct tag_2 {};
char * p = fmtlib::format(buf, 42);
p = fmtlib::format(p, ' ');
p = fmtlib::format(p, "is the answer"s);
p = fmtlib::format(p, ';' );
p = fmtlib::format(p, one::point<int>{3,4});
p = fmtlib::format(p, '-' );
p = fmtlib::format(p, one::point<float>{0.1,-1.2});
p = fmtlib::format(p, ';' );
p = fmtlib::format(p, two::value_holder<short, tag_1>{333});
p = fmtlib::format(p, '-' );
p = fmtlib::format(p, two::value_holder<unsigned long long, tag_2>{555});
*p = 0;
std::cout << "Result: " << buf << std::endl;
}
Проверялось на g++-11 в режиме C++17 |