Click here to Skip to main content
Click here to Skip to main content
Go to top

Functor and Member Function Pointer

, 12 Jan 2010
Rate this:
Please Sign up or sign in to vote.
An article on using a C++ template functor and a member function pointer.

The Problem

Suppose you need to use a legacy C++ class designed in COM style. Some methods of the class return HRESULT, and take a pointer as a parameter that could point to an int, a short, a std::string, an enum, and so on. For example:

HRESULT GetName(std::string* name);

Solution 1

The most obvious way of calling this method is:

std::string name;
if (SUCCEEDED(obj->GetName(&name)))
    m_name = name;
else
    m_name = "Untitled";

If you call the methods over and over again using this way, you will create quite a bit of duplicated code.

Solution 2

One way to solve this is to provide a helper function for the methods that have the same parameter type. For example, for the methods that take int* as the parameter, you could write a helper function, something like follows:

int GetInt(MyClass* obj, HRESULT (MyClass::*func)(int*), int defaultValue)
{
    int i = defaultValue;

    if (SUCCEEDED(obj->*func(&i))) // call the member method
        return i;
    else
        return defaultValue;
}

The obj parameter points to a MyClass object on which the member method is to be called; the func parameter points to a member method of MyClass to be called; the defaultValue parameter is to be returned if the function call to the member method fails. The helper function hides the details of checking the HRESULT returned from the member method.

You can now use the helper function when you need to call a method on a MyClass object, e.g.:

int length = GetInt(obj, &MyClass::GetLength, 0);

The code for calling the GetName() method can be reduced to:

m_name = GetString(obj, &MyClass::GetName, "Untitled");

The code becomes much more concise. However, there is a problem: you need to write a helper function for each group of methods of each class, where each group of methods has the same parameter type. Let’s say, you have five classes and all of them have methods that use 10 different parameter types, then you have to create 50 helper functions, which is quite a bit of (seemingly duplicated) code.

A Better Solution

Is there a better solution? Yes, by using a combination of template and member function pointers. We can define a template Functor class PropertyGetter:

///////////////////////////////////////////////////////////////////////////////
// A Functor for calling member methods that returns HRESULT and takes a
// pointer as the parameter, e.g. HRESULT MyClass::GetLength(int* length)
//
// T represents a class whose method is to be called.
// ARG represents the type of the parameter of the method to be called.
///////////////////////////////////////////////////////////////////////////////
template<typename T, typename ARG>
class PropertyGetter
{
    T* m_object; // The object on which the method is to be called
    HRESULT (T::*m_func)(ARG*); // The member method to be called

public:
    PropertyGetter(T* obj, HRESULT (T::*func)(ARG*))
      : m_object(obj), m_func(func)
    {
    }

    ARG operator()(ARG defaultValue)
    {
        ARG a = defaultValue;
        if (SUCCEEDED((m_object->*m_func)(&a))) // call the member method
        {
            return a;
        }
        else
        {
            return defaultValue;
        }
    }
};

The template parameter T represents a class whose methods you want to call, and ARG represents the type of the parameter of a method. The constructor takes two parameters: a pointer to a class instance and a pointer to a member method. The operator() calls the target method on the class instance. If the call succeeds, it returns the value returned from the method; otherwise, it returns the defaultValue passed in.

With this template class, you can call any method of any class, as long as the method returns HRESULT and takes a pointer as the parameter. The GetName() and GetLength() methods can now be called as:

m_name = PropertyGetter<MyClass, std::string>(obj,
    &MyClass::GetName)("Untitled");

int length = PropertyGetter<MyClass, int>(obj, &MyClass::GetLength)(0);

which can be conceptually translated into:

{
    PropertyGetter<MyClass, std::string> temp1(obj, &MyClass::GetName);
    m_name = temp1("Untitled");
}

int length;
{
    PropertyGetter<MyClass, int> temp2(obj, &MyClass:GetLength);
    length = temp2(0);
}

As you can see in this example, when used properly, the combination of template and function pointers can help you make your code more concise.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Wu Xuesong
Software Developer (Senior) Rockwell Automation
Singapore Singapore
He is a Software Engineer at Rockwell Automation Asia Pacific Business Center, working on RSLogix 5000. Prior to joining Rockwell Automation, he had worked for Sybase for 8 years and was the original architect of the PowerBuilder Native Interface and the PowerBuilder .NET Compiler that can compile PowerBuilder applications to .NET Windows Forms or Web Forms applications. The programming languages he has used or is using intensively include C#, C++, C and 8086 assembly.
 
Wu XueSong's Blog

Comments and Discussions

 
QuestionWhy not a template function? PinmemberPaolo Messina16-Jan-10 5:39 
AnswerRe: Why not a template function? PinmemberWu Xuesong17-Jan-10 14:08 
GeneralRe: Why not a template function? PinmemberLim Bio Liong17-Jan-10 17:28 
GeneralRe: Why not a template function? PinmemberWu Xuesong17-Jan-10 18:11 
GeneralRe: Why not a template function? PinmemberLim Bio Liong17-Jan-10 19:11 
GeneralRe: Why not a template function? PinmemberPaolo Messina18-Jan-10 21:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 12 Jan 2010
Article Copyright 2010 by Wu Xuesong
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid