The project has a wrapper written for BSTR
.
// WinString.cpp
#include <iostream>
#include <string>
#include <comdef.h>
#include <OleAuto.h>
#include <atlconv.h>
#include <atlbase.h>
#define FMT_HEADER_ONLY
#include <fmt/format.h>
#include <fmt/xchar.h>
#pragma warning(disable: 4996)
namespace Win
{
class WinString
{
public:
WinString() : buffer{nullptr} {};
explicit WinString(const std::wstring& src) : buffer{::SysAllocString(src.data())} {}
explicit WinString(const std::string& src){
buffer = SysAllocString(CA2W(src.c_str()));;
}
~WinString()
{
if (buffer)
{
SysFreeString(buffer);
}
}
std::wstring ToWstring() const
{
return buffer ? std::wstring{buffer, ::SysStringLen(buffer)} : std::wstring{};
}
std::string ToString() const
{
_bstr_t bstr_t(buffer, false);
return std::string(bstr_t);
}
private:
BSTR buffer;
};
}
Using WinString
type by default was giving the following error.
error C2338: Cannot format an argument. To make type T formattable provide a formatter<T> specialization:
This is my first time using this library so I read couple of use cases on writing custom formatter for User Defined Types.
- https://wgml.pl/blog/formatting-user-defined-types-fmt.html#specifying-formatting-for-user-defined-types
- https://github.com/CelestiaProject/Celestia/blob/master/src/cel3ds/3dsread.cpp
I added the following code in, in hopes that it will solve the problem, but it is still giving me same error.
namespace fmt{
template<>
struct formatter<Win::WinString>
{
template<typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(Win::WinString const& winstr, FormatContext& ctx)
{
return fmt::format_to(ctx.out(), L"{}", winstr.ToWstring());
}
};
}
Is my implementation wrong or am I missing something?
Update:
I just added one constructor and a member function for std::string
to see if it works in case of std::string
and modified the format
function as below and it worked for std::string
template <typename FormatContext>
auto format(Win::WinString const& winstr, FormatContext& ctx)
{
return fmt::format_to(ctx.out(), "{}", winstr.ToString());
}
How can I make it work with wstring
?
WinString is being passed to a function which tries to use it with wstring
, I want to make it work the following way.
int main()
{
const std::wstring& value{L"Something something dark side!"};
Win::WinString comStr{value};
std::wcout << fmt::format(L"The emperor {} says {}\n", 1, comStr);
}
CodePudding user response:
formatter
is specialized on the type you want to format and the code unit type which is char
by default so to make it work with wide strings pass wchar_t
as a second template parameter:
template <>
struct fmt::formatter<Win::WinString, wchar_t> {
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Win::WinString & winstr, FormatContext& ctx) {
return fmt::format_to(ctx.out(), L"{}", winstr.ToWstring());
}
};