By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,159 Members | 913 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,159 IT Pros & Developers. It's quick & easy.

Overload resolution & boost::bind

P: n/a
The program below contains a compile error. Following the program you
will find the typical fix then my idea for a library that facilitates
a more elegant fix.

#include <boost\bind.hpp>

using namespace boost;

struct C
{
void F(char, char){}
void F(int, int){}
void F(char, int){}
void F(char){}
};

int main()
{
C o;
bind(
C::F, // error: which C::F?
&o,
_1
);
}

Typical solution:

bind(static_cast<void (C::*)(char)>(C::F), &o, _1);

And if you're a nice guy:

typedef void (C::* MemFun1Char)(char);
bind(static_cast<MemFun1Char>(C::F), &o, _1);

If we had these...:

template<typename TC, typename TR>
TR (TC::* resolve_cast0(TR (TC::* pFunc)(void)))(void)
{
return pFunc;
}

template<typename TP, typename TC, typename TR>
TR (TC::* resolve_cast1(TR (TC::* pFunc)(TP)))(TP)
{
return pFunc;
}

template<typename TP1, typename TP2, typename TC, typename TR>
TR (TC::* resolve_cast2(TR (TC::* pFunc)(TP1, TP2)))(TP1, TP2)
{
return pFunc;
}

template<typename TP1,
typename TP2,
typename TP3,
typename TC,
typename TR>
TR (TC::* resolve_cast3(TR (TC::* pFunc)(TP1, TP2, TP3)))(TP1,

TP2,

TP3)
{
return pFunc;
}

....etc; the bind call would look like this:

bind(resolve_cast1<char>(C::F), &o, _1);

Benefits:
1.) No ugly syntax due to specifying member function pointer type with
static_cast.
or
2.) One less line of code due to no typedef.

Another example; if I want to specify C::F(char, int):

bind(resolve_cast2<char, int>(C::F), &o, _1, _2);

Now, if we had this...:

struct D
{
void F(char, char){}
void F(char){}
};

....things would be even nicer:

If I want to call D::F(char, char):

bind(
resolve_cast2(D::F), //notice no template params specified.
&o,
_1,
_2);

If I want to call D::F(char):

bind(resolve_cast1(D::F), &o, _1);

It would be nice to do this, but I can't find a way:

If I want to call C::F(char):

bind(
resolve_cast<char>(C::F), // notice no number appended
&o,
_1);

If I want to call D::F(char, char):

bind(
resolve_cast<2>(D::F), // notice no number appended
&o,
_1);
Has anyone seen this before?
Do you think this is worth having in a library?
Is it possible to implement a form without a number appended?
Is there a name better than resolve_cast?

This was tested only in VC7.1.
Jul 22 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
"Arturo Cuebas" <acuebas@NO_SPAM.houston.rr.com> wrote in message
news:8c********************************@4ax.com...
The program below contains a compile error. Following the program you
will find the typical fix then my idea for a library that facilitates
a more elegant fix.

#include <boost\bind.hpp>

using namespace boost;

struct C
{
void F(char, char){}
void F(int, int){}
void F(char, int){}
void F(char){}
};

int main()
{
C o;
bind(
C::F, // error: which C::F?
&o,
_1
);
}

Typical solution:

bind(static_cast<void (C::*)(char)>(C::F), &o, _1);

And if you're a nice guy:

typedef void (C::* MemFun1Char)(char);
bind(static_cast<MemFun1Char>(C::F), &o, _1);

[snipped solution involving templates]

While I admit that function pointer syntax can be ugly, the solution that
you proposed is unnecessary. IMHO, elegance is not measured in terms of
casts or punctuation symbols. While your proposed solution does eliminate
the function signature from the caller's code, it makes the caller's code
harder to follow. The proposed solution makes it harder to determine which
function is being called because the resolution is hidden by a template
function. Also, the solution does not eliminate the author's need to figure
out which function he/she needs to call, so it doesn't make anything easier
for him/her. In the end, the cure is worse than the disease.

--
David Hilsee
Jul 22 '05 #2

P: n/a
On Sat, 14 Aug 2004 01:31:19 -0400, "David Hilsee"
<da*************@yahoo.com> wrote:
"Arturo Cuebas" <acuebas@NO_SPAM.houston.rr.com> wrote in message
news:8c********************************@4ax.com.. .
The program below contains a compile error. Following the program you
will find the typical fix then my idea for a library that facilitates
a more elegant fix.

#include <boost\bind.hpp>

using namespace boost;

struct C
{
void F(char, char){}
void F(int, int){}
void F(char, int){}
void F(char){}
};

int main()
{
C o;
bind(
C::F, // error: which C::F?
&o,
_1
);
}

Typical solution:

bind(static_cast<void (C::*)(char)>(C::F), &o, _1);

And if you're a nice guy:

typedef void (C::* MemFun1Char)(char);
bind(static_cast<MemFun1Char>(C::F), &o, _1);[snipped solution involving templates]

While I admit that function pointer syntax can be ugly, the solution that
you proposed is unnecessary. IMHO, elegance is not measured in terms of
casts or punctuation symbols.


I misused the word "elegant". Maybe "syntactically prettier" would
have been more appropriate.
While your proposed solution does eliminate
the function signature from the caller's code, it makes the caller's code
harder to follow. The proposed solution makes it harder to determine which
function is being called because the resolution is hidden by a template
function.
You have to explicitly specify the parameter types of the function you
want the template to resolve the overload to. This explicit
specification of the parameter types puts which function you want
called right in your face.

Consider:

resolve_cast1<char>(C::F)

- The number indicates how many parameters the function you want
called takes (incidentally, I don't like this, I wish I could have
done resolve_cast<1, char>(C::F) or even resolve_cast<char>(C::F), but
I couldn't figure it out).

- The template parameter(s) indicate what the parameter types are of
the function you want to call.

These two aspects make it clear as day which function you want to
call: The overload of F that takes 1 parameter of type char.

Now, consider:

static_cast<void (C::*)(char)>(C::F)

Read from left to right (disregarding the parens and angle brackets):

"void" - The return type of the overloaded function - just because
it's part of the type you're casting to it has to be specified.

"C" - The class the function belongs to. Again, just because it's part
of the type you're casting to it has to be specified. Also, this is
redundant, as it is already specified in the "parameter" to
static_cast.

"::*" - Would you mind if all I said about this is "ugh"?

char - Now we've finally got to the part that truly differentiates the
function we want from the rest of the functions.

The parameter types are the only differences between functions that
allow the functions to be overloaded therefore it makes a certain
sense that that is the only thing the coder should have to specify -
and with this facility, that's all the coder has to.
Also, the solution does not eliminate the author's need to figure
out which function he/she needs to call,
psycic_resolve_cast<>?
so it doesn't make anything easier for him/her.
I think it's easier to follow this:

resolve_cast1<char>(C::F)

than this:

static_cast<void (C::*)(char)>(C::F)

but that's just me. Maybe it just takes a little familiarity with what
resolve_cast1<> does, just like it takes a little familiarity with
lexical_cast<> and numeric_cast<> to know what they do.
In the end, the cure is worse than the disease.


Jul 22 '05 #3

P: n/a
"Arturo Cuebas" <acuebas@NO_SPAM.houston.rr.com> wrote in message
news:1r********************************@4ax.com...
<snip>
I think it's easier to follow this:

resolve_cast1<char>(C::F)

than this:

static_cast<void (C::*)(char)>(C::F)

but that's just me. Maybe it just takes a little familiarity with what
resolve_cast1<> does, just like it takes a little familiarity with
lexical_cast<> and numeric_cast<> to know what they do.


By the way, I believe you're missing the ampersands in your code (&C::F).

Keep in mind that it doesn't "do" anything. The other two actually provide
some functionality (conversion and range checking). The resolve_cast1
function template just provides an alternate syntax for specifying which
overload should be used. If you like it, that's fine, but I'm not
impressed. Function pointer syntax doesn't disgust me to the point where I
feel like it must be hidden behind template code, and the tiny bit of
redundancy doesn't bother me, either. Don't take it personally. I
generally object to additional code that is merely for aesthetics and has
little to no technical benefit.

--
David Hilsee
Jul 22 '05 #4

P: n/a
Arturo,

You might want to repost this on the boost mailing lists. You may get some
insights from the authors.

Jeff F

"Arturo Cuebas" <acuebas@NO_SPAM.houston.rr.com> wrote in message
news:8c********************************@4ax.com...
The program below contains a compile error. Following the program you
will find the typical fix then my idea for a library that facilitates
a more elegant fix.

#include <boost\bind.hpp>

using namespace boost;

struct C
{
void F(char, char){}
void F(int, int){}
void F(char, int){}
void F(char){}
};

int main()
{
C o;
bind(
C::F, // error: which C::F?
&o,
_1
);
}

Typical solution:

bind(static_cast<void (C::*)(char)>(C::F), &o, _1);

And if you're a nice guy:

typedef void (C::* MemFun1Char)(char);
bind(static_cast<MemFun1Char>(C::F), &o, _1);

If we had these...:

template<typename TC, typename TR>
TR (TC::* resolve_cast0(TR (TC::* pFunc)(void)))(void)
{
return pFunc;
}

template<typename TP, typename TC, typename TR>
TR (TC::* resolve_cast1(TR (TC::* pFunc)(TP)))(TP)
{
return pFunc;
}

template<typename TP1, typename TP2, typename TC, typename TR>
TR (TC::* resolve_cast2(TR (TC::* pFunc)(TP1, TP2)))(TP1, TP2)
{
return pFunc;
}

template<typename TP1,
typename TP2,
typename TP3,
typename TC,
typename TR>
TR (TC::* resolve_cast3(TR (TC::* pFunc)(TP1, TP2, TP3)))(TP1,

TP2,

TP3)
{
return pFunc;
}

...etc; the bind call would look like this:

bind(resolve_cast1<char>(C::F), &o, _1);

Benefits:
1.) No ugly syntax due to specifying member function pointer type with
static_cast.
or
2.) One less line of code due to no typedef.

Another example; if I want to specify C::F(char, int):

bind(resolve_cast2<char, int>(C::F), &o, _1, _2);

Now, if we had this...:

struct D
{
void F(char, char){}
void F(char){}
};

...things would be even nicer:

If I want to call D::F(char, char):

bind(
resolve_cast2(D::F), //notice no template params specified.
&o,
_1,
_2);

If I want to call D::F(char):

bind(resolve_cast1(D::F), &o, _1);

It would be nice to do this, but I can't find a way:

If I want to call C::F(char):

bind(
resolve_cast<char>(C::F), // notice no number appended
&o,
_1);

If I want to call D::F(char, char):

bind(
resolve_cast<2>(D::F), // notice no number appended
&o,
_1);
Has anyone seen this before?
Do you think this is worth having in a library?
Is it possible to implement a form without a number appended?
Is there a name better than resolve_cast?

This was tested only in VC7.1.

Jul 22 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.