This is a problem I found when trying to over come a simple desire to have a small sized class that it would be best to move around by value rather than reference. The idea was to have base functions using one type and a conversion operator to allow for the other type to also be its argument.
Yes this is abusing what templates are for, but the code did not need duplication. It also got this complex because C++ does not allow structure casts/conversion operators.
#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdlib.h> #include <stdint.h> #include <memory.h> // forward declaration. class utf16; struct utf8Span { utf8Span() = default; // ZII operator const char*() { return (const char*)m_span; }; utf8Span(uint8_t* text) : m_span(text){}; uint8_t* m_span{0}; }; struct utf16Span { utf16Span() = default; // ZII operator const wchar_t*() { return (const wchar_t*)m_span; }; utf16Span(uint8_t* text) : m_span(text){}; uint8_t* m_span{0}; }; class utf8 { public: utf8() { m_text = 0; m_utf8Span.m_span = 0; m_utf16Span.m_span = 0; }; // ZII operator const char*() { return (const char*)m_text; }; operator const utf8Span() { return m_utf8Span; }; utf8(utf16Span text16Span); utf8(const char* text) { size_t size = strlen(text) + 1; m_text = (uint8_t*)malloc(size); memcpy(m_text, text, size); } utf8& operator=(const utf8& that) { if (m_text == nullptr) free(m_text); size_t size = strlen((const char*)that.m_text) + 1; m_text = (uint8_t*)malloc(size); memcpy(m_text, that.m_text, size); } utf8(const utf8& that) { if (m_text == nullptr) free(m_text); size_t size = strlen((const char*)that.m_text) + 1; m_text = (uint8_t*)malloc(size); memcpy(m_text, that.m_text, size); } ~utf8() { if (m_text == nullptr) free(m_text); } protected: union { utf8Span m_utf8Span{0}; uint8_t* m_text; utf16Span m_utf16Span; }; }; class utf16 : protected utf8 { public: operator const wchar_t*() { return (const wchar_t*)m_text; }; operator const utf16Span() { return m_utf16Span; }; utf16(utf8Span text8Span) { uint8_t* bytes = (uint8_t*)(const char*)text8Span; size_t size = 2 * (strlen((const char*)text8Span) + 1); m_text = (uint8_t*)calloc(size, 1); for (size_t i = 0; i < size; i += 2) m_text[i] = bytes[i/2]; } utf16(const wchar_t* text16) { size_t size = 2* (wcslen(text16) + 1); m_text = (uint8_t*)malloc(size); memcpy(m_text, text16, size); } utf16& operator=(const utf16& that16) { if (m_text == nullptr) free(m_text); size_t size = 2 * (wcslen((wchar_t*)that16.m_text) + 1); m_text = (uint8_t*)malloc(size); memcpy(m_text, that16.m_text, size); } utf16(const utf16& that16) { if (m_text == nullptr) free(m_text); size_t size = 2 * (wcslen((wchar_t*)that16.m_text) + 1); m_text = (uint8_t*)malloc(size); memcpy(m_text, that16.m_text, size); } ~utf16() { if (m_text == nullptr) free(m_text); } }; utf8::utf8(utf16Span text16Span) { uint8_t* bytes = (uint8_t*)(const wchar_t*)text16Span; size_t size = wcslen(text16Span) + 1; m_text = (uint8_t*)calloc(size, 1); for (size_t i = 0; i < size; i++) m_text[i] = bytes[i*2]; } int main() { utf8 aaWord8("This"); utf8 aaNext8 = aaWord8; utf8 aaAgain8 = utf8("Again"); utf16 aaWord16(L"This"); utf16 aaNext16 = aaWord16; utf16 aaAgain16 = utf16(L"Again"); utf8Span aaWord8Span((uint8_t*)((const char *)aaWord8 + 1)); utf16Span aaWord16Span((uint8_t*)((const wchar_t *)aaWord16 + 1)); utf16 aaMade16(aaWord8Span); utf8 aaMade8(aaWord16Span); utf16 aaMade16a(aaWord8); utf8 aaMade8a(/*(utf16Span)*/aaWord16); return 0; }