Introduction
std::function
is defined in the functional header, it is a polymorphic class template wrapper. It can store any callable target. We can consider it to be a super set of a function pointer as it can store objects too.
Using std::function
we can create our new functional signature using std::bind
.
Let us go straight for the std::function
declaration.
std::function< FunctionSignature > FunctionObject = FunctionReference;
Here,
FunctionSignature
is the signature of the function we are binding to. FunctionObject
is an object of the template we have defined. FunctionReference
is the reference of the function we want to create.
Using the code
For this tip, I have created two functions which I am going to use throughout the tip:
void WriteToConsoleScreen(std::wstring szMyName)
{
wprintf(_T("my name is %s \n"),szMyName.c_str());
}
void WriteToConsoleScreenWithAge(std::wstring szMyName,int age)
{
wprintf(_T("my name is %s and age equal to %d\n"),szMyName.c_str(),age);
}
Example # 1: Storing normal functions
std::function<void(std::wstring)> fnwriteToConsoleScreen = WriteToConsoleScreen;
fnwriteToConsoleScreen(_T("VisualCPP"));
Similarly in a function pointer, we have to use this code…
typedef void (*MySingleArgFunction) (std::wstring);
MySingleArgFunction fnwriteToConsoleScreen1 = WriteToConsoleScreen;
fnwriteToConsoleScreen1(_T("VisualCPP"));
Example # 2: Storing using function lambdas
We can use the C++11 feature lambdas in std::function
, which is a little typical in a function pointer, and having an object pointing to an anonymous function we can use it again and again.
std::function<void(std::wstring)> fnwriteToConsoleScreen = [](std::wstring szMyName){
wprintf(_T("my name is %s \n"),szMyName.c_str());
};
fnwriteToConsoleScreen(_T("VisualCPP"));
In the below example, I am passing the parent variable in our lambda function:
int age =30;
std::function<void(std::wstring)> fnwriteToConsoleScreen2 = [age](std::wstring szMyName){
wprintf(_T("my name is %s and age is %d \n"),szMyName.c_str(),age);
};
fnwriteToConsoleScreen2(_T("VisualCPP"));
I am using the auto
keyword to create a named object for the anonymous method, it creates a variable almost equivalent to the function pointer.
auto fnwriteToConsoleScreen3 = [](std::wstring szMyName){
wprintf(_T("my name is %s \n"),szMyName.c_str());
};
fnwriteToConsoleScreen3(_T("VisualCPP"));
Example # 3: Storing using std::bind
std::bind
helps you bind a variable to a function. It comes very handy when you want to have your own function signature instead of a defined function. It provides functionality like an optional parameter. In the first example, I bind the constant value using std::bind
, you can see now that my function object calling signature has been changed from void(std::wstring)
to void()
as I have already bound my argument value at runtime.
std::function<void()> fnwriteToConsoleScreen_staticarg = std::bind(WriteToConsoleScreen, _T("VisualCPP"));
fnwriteToConsoleScreen_staticarg();
Similar to the previous one, however I have bound the variable instead of the constant value.
std::wstring strDynamicArg = _T("VisualCPPDynamic");
std::function<void()> fnwriteToConsoleScreen_dynamicarg = std::bind(WriteToConsoleScreen, strDynamicArg);
fnwriteToConsoleScreen_dynamicarg();
As mentioned in the start of the example, we can declare placeholders, which work like optional parameters; however it’s not restricted to the right side. For using a placeholder, we have to use its namespace std::placeholders
, which provides the declaration for _1, _2, _3, etc. It would be useful in a condition when you have to call a function whose one argument is constant throughout the programming scope and another argument keeps changing based on some condition and you have no authority over the base function. Now let us see a case for WriteToConsoleScreenWithAge
, where I want my string argument to be constant and age to be different. In traditional programming we will pass string
and int
arguments every-time we call the function, however using std::bind
we can create a functional template where we specify the string argument and keep place of the placeholder age
.
using namespace std::placeholders;
auto fnwriteToConsoleScreen_PlaceHolderarg = std::bind(WriteToConsoleScreenWithAge, _T("VisualCPP"),_1);
fnwriteToConsoleScreen_PlaceHolderarg(30);
Above _1
is placeholder for age, which could be specified every time we call the function object.
Example # 4: Using class function and functor
For this example I have defined a class like this:
class ConsoleFunctor
{
public:
ConsoleFunctor()
{
}
void operator()(std::wstring szMyName)
{
wprintf(_T("my name is %s \n"),szMyName.c_str());
};
void WriteToConsoleWithAge(std::wstring szMyName,int age)
{
wprintf(_T("my name is %s and age equal to %d\n"),szMyName.c_str(),age);
}
};
We can create a function object for a functor like this:
ConsoleFunctor functObject;
std::function<void(std::wstring)> fnWriteToConsole(functObject);
fnWriteToConsole(_T("VisualCPP with existingObject"));
First we create an object of the function and then pass that object to a functional template and call functionObject
normally to invoke functor
. And for calling the class function using the functional template, we can use the following code:
std::function<void(const ConsoleFunctor,std::wstring,int)>
fnWriteToConsole1 = &ConsoleFunctor::WriteToConsoleWithAge;
fnWriteToConsole1(functObject,_T("VisualCPP with existingObject"),30);
Points of Interest
std::function
is the interesting piece of code, it could come handy in various conditions. Hope we hear more development about this in future.