Asking for trouble

Started by
5 comments, last by stylin 18 years, 6 months ago
Here are two of the constructors for a class I have:

/** 
 * Constructor that inits the color when given the four parts.
 * \param a Unsigned integer value from 0-255 representing the alpha value of the color.
 * \param r Unsigned integer value from 0-255 representing the red value of the color.
 * \param g Unsigned integer value from 0-255 representing the green value of the color.
 * \param b Unsigned integer value from 0-255 representing the blue value of the color.
 */
CColor(unsigned int a, unsigned int r, unsigned int g, unsigned int b)
{
	// Set the color
	set(a, r, g, b);
}

/**
 * Constructor
 * \param a Float value from 0.0f-1.0f representing the alpha value of the color.
 * \param r Float value from 0.0f-1.0f representing the red value of the color.
 * \param g Float value from 0.0f-1.0f representing the green value of the color.
 * \param b Float value from 0.0f-1.0f representing the blue value of the color.
 */
CColor(float a, float r, float g, float b)
{
	// set the color
	set(a, r, g, b);
}


Now, often when I call them, I have problems because ints are promoted to floats. Is there a way of writing the constructors so that I don't have to explcitly define where I call the functions?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Advertisement
Well, here you have ambiguous function definitions. You can either change your parameter types from "unsigned int" to "int", or, you can specify which one you want to use explicitly (which you don't want to do):

CColor colorA((unsigned int)1, (unsigned int)2, (unsigned int)3, (unsigned int)4);CColor colorB(1U, 2U, 3U, 4U);


Pick your poison :x
Parameterize your CColor class.

EDIT: Or better yet, specialize a function template:
namespace Endar {   class color { /*...*/ };   template< typename T >   color get_color( T a, T r, T g, T b );   typedef unsigned char byte_range;   typedef float normalized_range;   template<>   color get_color( byte_range a, byte_range r, byte_range g, byte_range b ) {//    ...                       // code for converting 0...255 color ranges to                                // whatever format color uses      return color( /*...*/ );   }   template<>   color get_color( normalized_range a, normalized_range r, normalized_range g, normalized_range b ) {//    ...                       // code for converting 0.0...1.0 color ranges to                                // whatever format color uses      return color( /*...*/ );   }}int main() {	using Endar::byte_range;	using Endar::normalized_range;	// use both types of input to create colors        Endar::color color1 = Endar::get_color( byte_range(0), byte_range(63), byte_range(127), byte_range(255) );	Endar::color color2 = Endar::get_color( normalized_range(0.0), normalized_range(0.25), normalized_range(0.5), normalized_range(1.0) );	return 0;}


[Edited by - stylin on October 24, 2005 5:43:41 AM]
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid
Haven't used this in ages, so I'm not 100% sure, but isn't this where you'd use the explicit keyword?

Something like
explicit CColor(unsigned int a, unsigned int r, unsigned int g, unsigned int b)explicit CColor(float a, float r, float g, float b)
Quote:Original post by Spoonbender
Haven't used this in ages, so I'm not 100% sure, but isn't this where you'd use the explicit keyword?

Something like
*** Source Snippet Removed ***

The explicit keyword eliminates implicit conversions. You use it in situations where you want to limit usage. For example:
   class some_class {      public:         explicit some_class( int );         some_class( float );   };   ...   some_class sc1 = 3;   // float version is used since there are no implicit                         // conversions from int to some_class.

The above is like saying, "you can convert a float into a some_class, but in order to convert an int to a some_class you must do it explicitly."

So, you can see the problem if you make both constructors explicit; the only way to convert to a some_class from either format would be to do it explicitily:
some_class sc1 = static_cast< some_class > ( 3 );         // uses int versionsome_class sc2 = static_cast< some_class > ( 3.0f );      // uses float version

Anything else won't compile because of the explicit constructors.
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid
Quote:Original post by stylin
So, you can see the problem if you make both constructors explicit; the only way to convert to a some_class from either format would be to do it explicitily:
some_class sc1 = static_cast< some_class > ( 3 );         // uses int versionsome_class sc2 = static_cast< some_class > ( 3.0f );      // uses float version

Anything else won't compile because of the explicit constructors.


Actually, some_class sc1(3); would compile fine, as would some_class sc1(3.0f);. You don't need to use an equal sign to initialize a variable, just as you could do some_class(int, int) and then some_class ClassInstance(3,2);. But the meat of your post is true.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Quote:Original post by Erzengeldeslichtes
Quote:Original post by stylin
So, you can see the problem if you make both constructors explicit; the only way to convert to a some_class from either format would be to do it explicitily:
some_class sc1 = static_cast< some_class > ( 3 );         // uses int versionsome_class sc2 = static_cast< some_class > ( 3.0f );      // uses float version

Anything else won't compile because of the explicit constructors.


Actually, some_class sc1(3); would compile fine, as would some_class sc1(3.0f);. You don't need to use an equal sign to initialize a variable, just as you could do some_class(int, int) and then some_class ClassInstance(3,2);. But the meat of your post is true.

True, and I was addressing the situations in which the explicit keyword is relavent, as it has no bearing on explicitly-called constructors. By "anything" I meant any form of copy assignment/assignment, in which implicit conversions are taking place, hence the purpose of the explicit keyword. Should have clarified - good heads up.
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid

This topic is closed to new replies.

Advertisement