Sign in to follow this  

A templated cross-type copy constructor question

This topic is 1953 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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:

[b]typedef IColorBase<float> IColor;[/b]

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:

[b]IColor color = RGB(0, 255, 0);[/b]

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

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

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

[b]typedef IColorBase<BYTE> IRGBA;[/b]

Whose copy constructor would look like this:

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

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 [i]something like[/i] this:

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

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.

Share this post


Link to post
Share on other sites
I looks like you're looking for [i]template specialization[/i], and you've almost got the syntax right:[code]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); }[/code]

Share this post


Link to post
Share on other sites
[quote name='irreversible' timestamp='1347195384' post='4978289']
I have a color class called IColor, which extends from an IColorBase template class like:

[b]typedef IColorBase<float> IColor;[/b]
[/quote]
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]."

[quote name='irreversible' timestamp='1347195384' post='4978289']
RGB() is a macro that splices byte components into a DWORD. The copy constructor looks like this:

[b]IColorBase(DWORD& clr) { BYTE* _c = (BYTE*)&clr; r = _c[0] / 255.f; g = _c[1] / 255.f; b = _c[2] / 255.f; a = 1; }[/b]
[/quote]
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.

[quote name='irreversible' timestamp='1347195384' post='4978289']
Whose copy constructor would look like this:

[b]IColorBase(DWORD& clr) { BYTE* _c = (BYTE*)&clr; r = _c[0]; g = _c[1]; b = _c[2]; a = 255; }[/b]
[/quote]
Again, not a copy constructor.

[quote name='irreversible' timestamp='1347195384' post='4978289']
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 [i]something like[/i] this:

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

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.
[/quote]
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:
[code]
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%?
{
}
};
[/code]
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). Edited by Cornstalks

Share this post


Link to post
Share on other sites
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 :)

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

Yeah - that's a copy-paste thing.

Share this post


Link to post
Share on other sites
Sign in to follow this