Conversions when inherited and a constructor

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;
}

Reasons for Using C++ 17

Using the logic that we should use tools that are as simple as possible and only adopt complexity where it is absolutely necessary, it feels like I could use a very early version of C++. What follows are the reasons why I have increased that to C++17. The idea will be to only use these feature and no more. Any new use will be add to this page.

#if !((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
    #error Requires C++17 or higher
#endif
Continue reading “Reasons for Using C++ 17”

Asking Stack Overflow the best way to do Template Specialisation

In learning C++ I dug in and tried to use classes and templates to solve what feels like a typical use case. I found that what I needed was Template Specialisation and that C++ does not support this very well. I came up with 3 different methods and wanted to check what others though was we the best approach. If there was a “preferred idiom in C++”, or an even better solution.

Continue reading “Asking Stack Overflow the best way to do Template Specialisation”