+2  A: 

You don't really need to use the typedef. You're just using the typedef to create a name for a type, then using that type to define your pointer, and in a typecast to initialize the pointer. If you really want to, you can use the type directly for both of those, but you end up repeating the same (often lengthy) type for both the definition and the typecast. For a somewhat simplified, standalone example:

struct XXX {
    int member() { return 0; }
    int member(int) { return 1; }
};

int main() {     
    int (XXX::*pmfv)(void) = (int (XXX::*)())&XXX::member;
    int (XXX::*pmfi)(int) = (int (XXX::*)(int))&XXX::member;
    return 0;
}

While this is possible, and should be accepted by any properly functioning compiler, I can't say I'd really advise it -- while it creates and initializes the pointer in a single statement, if the type involved has a long name, it's probably going to end up as a couple of lines of code anyway, just due to the length.

I believe C++ 0x's, auto should allow the first example above to be shortened to something like this:

auto pmf = (int (XXX::*)())&XXX::member;

This should make it much easier to avoid the typedef (and depending on the compiler you're using, you may already have this available).

Jerry Coffin
Well, again, there's no need for a cast in this particular case, regardless of whether it uses a typedef or not. The compiler is required to select the proper overload even without a cast.
AndreyT
+2  A: 

What you're asking is similar to an earlier question, and the answer I gave there is relevant here as well.

From section 13.4/1 ("Address of overloaded function," [over.over]):

A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type matches the target type required in the context. The target can be

  • an object or reference being initialized (8.5, 8.5.3),
  • the left side of an assignment (5.17),
  • a parameter of a function (5.2.2),
  • a parameter of a user-defined operator (13.5),
  • the return value of a function, operator function, or conversion (6.6.3), or
  • an explicit type conversion (5.2.3, 5.2.9, 5.4).

The overload function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed. [Note: any redundant set of parentheses surrounding the overloaded function name is ignored (5.1). ]

In your case, the target from the above list is the third one, a parameter of your MakeObjGuard function. However, I suspect that's a function template, and one of the type parameters for the template is the type of the function pointer. The compiler has a Catch-22. It can't deduce the template parameter type without knowing which overload is selected, and it can't automatically select which overload you mean without knowing the parameter type.

Therefore, you need to help it out. You can either type-cast the method pointer, as you're doing now, or you can specify the template argument type explicitly when you call the function: MakeObjGuard<SelectObjectBitmap>(...). Either way, you need to know the type. You don't strictly need to have a typedef name for the function type, but it sure helps readability.

Rob Kennedy
The MakeObjGuard is similar to MakePair - I want the function to deduce the argument types and produce the correct template object for the given arguments (just as MakePair produces a std::pair<T1,T2>). So any "help" I have to give the MakeXXX function needs to be in its argument list, rather than manually selecting the resulting template (although this could be done, its antithetical).
Mordachai
I appreciate your problem, but you'd have the same trouble calling `make_pair` with an overloaded function pointer as you're having calling `MakeObjGuard`. The compiler can't deduce template types if it doesn't know the argument types.
Rob Kennedy
I am satisfied, at least for the moment, with the code I derived from yours and others help on the subject. You get the official answer for the most complete answer. Thanks again :)
Mordachai
+1  A: 

You can avoid using the typedef, but it really isn't pretty:

void foo(int){
    std::cout << "int" << std::endl;
}

void foo(float){
    std::cout << "float" << std::endl;
}

int main()
{
    typedef void (*ffp)(float);

    ffp fp = (void (*)(float)) foo; // cast to a function pointer without a typedef

    ((ffp)fp)(0);
}

Better to stick to the typedef.

Autopulated
A: 

You seem to be misunderstanding the root of the issue. As long as the concrete type on the receiving side of the assignment/initialization is known to the compiler, you are not supposed to make any effort to "select" it at all, If your typedef is defined as

typedef CBitmap * (CDC::* SelectObjectBitmap)(CBitmap*); 

then the initialization

SelectObjectBitmap pmf = &CDC::SelectObject; 

is required to invoke overload resolution and select the proper overloaded version of the function without the need for an explicit cast. This is actually only one place in C++ when overload resolution in the right-hand side of the expression/initialization depends on the left-hand side.

Of course, the same should work without a typedef.


OK, seeing that what you are actually doing is passing the address of the method to a template function as a dependent argument type: of course, in this case you have to either 1) select the proper overload by using a cast, or 2) fix the function parameter type by explicitly specifying the template argument.

Of course, you can just pre-select the proper overload by doing

SelectObjectBitmap pmf = &CDC::SelectObject; 

and then pass pmf to your template function.

AndreyT