0
101 Sep 07, 2005 at 12:54

Hey guys,

I just thought of experimenting with something today, a little variation on the named parameter idiom. It’s a bit bloated, but I’m just messing around a little bit. Anyway, I came across a problem, my first guess is that this might not be allowed by the language in the first place - in which case I can use the boost preprocessor library to make a number of constructors, but I’d prefer that to be the last resort.

The troublesome bit of code is this pices:

struct NullParameter {
NullParameter() {}
void operator () ( void* o ) const
{}
};

class Texture
{
template< class P0 , class P1, class P2, class P3 >
Texture( const P0& p0 = NullParameter(),
const P1& p1 = NullParameter(),
const P2& p2 = NullParameter(),
const P3& p3 = NullParameter() )
: m_width(0),
m_height(0),
m_name(""),
m_useColorKey(false),
m_colorKey(0),
m_colorKeyAlpha(0)
{
p0(this);
p1(this);
p2(this);
p3(this);
// this->create();
}
};


It compiles fine if I privide arguments to all the parameters, but if it’s not four, it complains about “does not take 3 arguments”. So this would work:

Texture t( Texture::argSize( 500, 600 ),
Texture::argFilename( "happy" ),
Texture::argFormat( Texture::TF_Float32 ),
Texture::argColorKey( 0x0, 0x0 ) );


But this would not:

Texture t( Texture::argSize( 500, 600 ),
Texture::argFilename( "happy" ),
Texture::argFormat( Texture::TF_Float32 ) );


So is there a way to solve this problem without making multiple constructors? Incase you’re wondering, Texture::argSize, Texture::argColorKey and the others are structures within the Texture class that overload operator () with a single parameter to a Texture*. The operator () overload is responsible for setting the private variables of the Texture object based on what was passed in at their time of construction: Eg: argColorKey would look like this:

class Texture
{
public:
//====
struct argColorKey {
//====
argColorKey( uint32 c, uint8 a ) : color(c), alpha(a)
{}
void operator () ( Texture* o ) const {
o->m_useColorKey = true;
o->m_colorKey = color;
o->m_colorKeyAlpha = alpha;
}
private:
uint32 color;
uint8 alpha;
};
};


#### 6 Replies

0
101 Sep 07, 2005 at 13:33

<s>Your code is fine, what compiler are you using?</s>

.edit: disregard that, looks like the constructor is not considered in the list of possible overloads for some reason… I’ll have a look in the C++ spec

.edit2: Hmpff, how stupid of me to forget:
14.8.2.4

-17- A template type-parameter cannot be deduced from the type of a function default argument. [Example:

template <class T> void f(T = 5, T = 7);
void g()
{
f(1);                   //  OK: call  f<int>(1,7)
f();                    //  error: cannot deduce  T
f<int>();               //  OK: call  f<int>(5,7)
}


About the solution, you could overload the , operator to create a list of ‘arguments’ to your function (then you’re going more in the direction of boost::parameter). The downside of this is that you’ll need extra parentheses around your argument list. Or you can use another operator, such as <<, to circumvent that.

0
101 Sep 07, 2005 at 15:26

This is just guessing … I might be making a fool of myself now :)

I’m trying to “move” the default parameter to the template part …

class Texture
{
template< class P0 = NullParameter, class P1 = NullParameter, class P2 = NullParameter, class P3 = NullParameter >
Texture( const P0& p0 = P0(),
const P1& p1 = P1(),
const P2& p2 = P2(),
const P3& p3 = P3() )


Bramz

0
101 Sep 07, 2005 at 15:35

Myself, I use a construct like following for the named parameter idiom:

class Texture
{
class Arg
{
public:
Arg(): width_(0), height_(0), filename_("") {}
Arg& size(int width, int height) { width_ = width; height_ = height_; return *this; }
Arg& filename(const std::string& name) { filename_(name); return *this;
private:
friend class Texture;
int width_;
int height_;
std::string filename_;
};

Texture(const Arg& iArgs):
width_(iArgs.width_),
height_(iArgs.height_),
filename_(iArgs.filename_)
{
}
};

Texture t(Texture::Args().size(256, 256).filename("foo"));


Of course, your problem is how you can do it the other way :)

0
101 Sep 07, 2005 at 16:13

@bramz

This is just guessing … I might be making a fool of myself now :)

Unfortunately, default template arguments are only allowed for class templates, not for function templates :wink:

0
101 Sep 07, 2005 at 16:18

@.oisyn

@bramz

This is just guessing … I might be making a fool of myself now :)

Unfortunately, default template arguments are only allowed for class templates, not for function templates :wink:

[snapback]20968[/snapback]

bummer :)

0
101 Sep 08, 2005 at 03:38

well that sucks…

About the solution, you could overload the , operator to create a list of ‘arguments’ to your function (then you’re going more in the direction of boost::parameter). The downside of this is that you’ll need extra parentheses around your argument list. Or you can use another operator, such as <<, to circumvent that.

Yeah those are solutions, another one would be to use the boost.preprocessor library to mechanically generate the different constructor overloads. but anyway, thatnks guys.