A templated cross-type copy constructor question

Started by
2 comments, last by irreversible 11 years, 7 months ago
This question actually bears little relevance to what I'm doing, but it did make me curious.

I have a color class called IColor, which extends from an IColorBase template class like:

typedef IColorBase<float> IColor;

IColorBase is a generic base class that provides the usual constructors and operator overloading and not much else. What got me interested, though, was handling a cross-type copy constructor like:

IColor color = RGB(0, 255, 0);

RGB() is a macro that splices byte components into a DWORD. The copy constructor looks like this:

IColorBase(DWORD& clr) { BYTE* _c = (BYTE*)&clr; r = _c[0] / 255.f; g = _c[1] / 255.f; b = _c[2] / 255.f; a = 1; }

My question, however, has to do with multi-type copy constructors. Let's say I also have:

typedef IColorBase<BYTE> IRGBA;

Whose copy constructor would look like this:

IColorBase(DWORD& clr) { BYTE* _c = (BYTE*)&clr; r = _c[0]; g = _c[1]; b = _c[2]; a = 255; }

Including two constructors that take the same input argument type, however, doesn't make sense without a specific type declaration. In other words, I'd need something like this:

IColorBase<float>(DWORD clr) { BYTE* _c = (BYTE*)&clr; r = _c[0] / 255.f; g = _c[1] / 255.f; b = _c[2] / 255.f; a = 1; }
IColorBase<BYTE>(DWORD clr) { BYTE* _c = (BYTE*)&clr; r = _c[0] / 255.f; g = _c[1] / 255.f; b = _c[2] / 255.f; a = 1; }

Which, of course, doesn't work. Is it possible to provide type-aware constructors like this or does the standard not allow it at all? After all, it's possible for assignment operators.
Advertisement
I looks like you're looking for template specialization, and you've almost got the syntax right:template<class T> struct Color
{
Color(uint i);
T r,g,b,a;
};

template<> Color<float>::Color(uint i) { r = (i&0xFF)/255.0f; }
template<> Color<ubyte>::Color(uint i) { r = (i&0xFF); }

I have a color class called IColor, which extends from an IColorBase template class like:

typedef IColorBase<float> IColor;

That's not quite an "extension" ("extension" implies it inherits from [font=courier new,courier,monospace]IColorBase[/font]). That's just a normal "[font=courier new,courier,monospace]IColor[/font] is a typedef for [font=courier new,courier,monospace]IColorBase<float>[/font]."


RGB() is a macro that splices byte components into a DWORD. The copy constructor looks like this:

IColorBase(DWORD& clr) { BYTE* _c = (BYTE*)&clr; r = _c[0] / 255.f; g = _c[1] / 255.f; b = _c[2] / 255.f; a = 1; }

That's not a copy constructor. It's just a normal constructor that takes a [font=courier new,courier,monospace]DWORD[/font]. Also, you should make it a [font=courier new,courier,monospace]const DWORD&[/font] because you can't bind a non-const reference to a temporary. Actually, you probably want to just take out the reference all together and just make it a normal [font=courier new,courier,monospace]DWORD[/font]. There won't be any benefit here from using a reference.

Also, I wish you made [font=courier new,courier,monospace]RGB()[/font] an inline function and not a macro... I hate macros. They have no respect for namespace scope or anything.


Whose copy constructor would look like this:

IColorBase(DWORD& clr) { BYTE* _c = (BYTE*)&clr; r = _c[0]; g = _c[1]; b = _c[2]; a = 255; }

Again, not a copy constructor.


Including two constructors that take the same input argument type, however, doesn't make sense without a specific type declaration. In other words, I'd need something like this:

IColorBase<float>(DWORD clr) { BYTE* _c = (BYTE*)&clr; r = _c[0] / 255.f; g = _c[1] / 255.f; b = _c[2] / 255.f; a = 1; }
IColorBase<BYTE>(DWORD clr) { BYTE* _c = (BYTE*)&clr; r = _c[0] / 255.f; g = _c[1] / 255.f; b = _c[2] / 255.f; a = 1; }

Which, of course, doesn't work. Is it possible to provide type-aware constructors like this or does the standard not allow it at all? After all, it's possible for assignment operators.

Hmmm... I don't see any difference between the two? Did you intent for the constructors for [font=courier new,courier,monospace]IColorBase<float>[/font] and [font=courier new,courier,monospace]IColorBase<BYTE>[/font] to be exactly identical? Because I would've thought [font=courier new,courier,monospace]IColorBase<BYTE>[/font]'s constructor would've looked something like this:

[font=courier new,courier,monospace]IColorBase<BYTE>(DWORD clr) { BYTE* _c = (BYTE*)&clr; r = _c[0]; g = _c[1]; b = _c[2]; a = 255; }[/font]

If this is indeed what you intended, you could use a helper kind of like this:

template <typename T>
struct IColorBaseHelper;


template <>
struct IColorBaseHelper<float>
{
static const float max = 1.0f; // You don't need min or max now, but this shows
static const float min = 0.0f; // you that you can put useful stuff here
static const float dword_convert = 255.0f;
};


template <>
struct IColorBaseHelper<BYTE>
{
static const BYTE max = 255; // You don't need min or max now, but this shows
static const BYTE min = 0; // you that you can put useful stuff here
static const BYTE dword_convert = 1;
};


template <typename T>
class IColorBase
{
T r, g, b, a;

public:
IColorBase(const DWORD clr) :
r((clr & 0x000000ff) / IColorBaseHelper<T>::dword_convert),
g(((clr & 0x0000ff00) >> 8) / IColorBaseHelper<T>::dword_convert),
b(((clr & 0x00ff0000) >> 16) / IColorBaseHelper<T>::dword_convert),
a(((clr & 0xff000000) >> 24) / IColorBaseHelper<T>::dword_convert) // Why not have RGB() set alpha to 100%?
{
}
};

The nice thing about this is that it doesn't require you to template-specialize the entire class, and allows you to just template-specialize the relevant part(s).
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Thanks for the replies, guys! I could probably have take it myself from "template specialization", though.

Cornstalks - you're right about it not being a copy constructor. In this case the word of the law does defeat the spirit of it :)


Did you intent for the constructors for IColorBase<float> and IColorBase<BYTE> to be exactly identical?
[/quote]

Yeah - that's a copy-paste thing.

This topic is closed to new replies.

Advertisement