#1 Crossbones+ - Reputation: 801
Posted 09 September 2012 - 06:56 AM
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.
#2 Moderators - Reputation: 13554
Posted 09 September 2012 - 08:04 AM
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); }
#3 Moderator* - Reputation: 5387
Posted 09 September 2012 - 08:10 AM
That's not quite an "extension" ("extension" implies it inherits from IColorBase). That's just a normal "IColor is a typedef for IColorBase<float>."I have a color class called IColor, which extends from an IColorBase template class like:
typedef IColorBase<float> IColor;
That's not a copy constructor. It's just a normal constructor that takes a DWORD. Also, you should make it a const DWORD& 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 DWORD. There won't be any benefit here from using a reference.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; }
Also, I wish you made RGB() an inline function and not a macro... I hate macros. They have no respect for namespace scope or anything.
Again, not a copy constructor.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; }
Hmmm... I don't see any difference between the two? Did you intent for the constructors for IColorBase<float> and IColorBase<BYTE> to be exactly identical? Because I would've thought IColorBase<BYTE>'s constructor would've looked something like this: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.
IColorBase<BYTE>(DWORD clr) { BYTE* _c = (BYTE*)&clr; r = _c[0]; g = _c[1]; b = _c[2]; a = 255; }
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).
Edited by Cornstalks, 09 September 2012 - 08:16 AM.
#4 Crossbones+ - Reputation: 801
Posted 11 September 2012 - 02:13 PM
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?
Yeah - that's a copy-paste thing.






