Examples about function pointer and callback function definition - c++

I'm learning about callback function in C++ and have some problems in understanding the initialization of a callback function such as
typedef void (CALLBACK *name)(int,int);
I think it looks very similar to the declaration of function pointer like this:
typedef void (*name)(int,int);
I have a simple example about how to call a function inside another function using the declaration of function pointer. The example converts a string to int and compare with anoter int. Then tells which one is bigger:
#include <stdio.h>
#include <stdlib.h>
int StrToInt(char* inputchar) //converting function
{
int outputint;
outputint = atoi(inputchar);
return outputint;
}
typedef int(*p)(char*); //declare function pointer
void IntCompare(p FuncP, char* inputchar, int b) //comparing function
{
int a;
a = FuncP(inputchar); //call converting function using function pointer
if (a<b)
{
printf("%d is bigger\n", b);
}
else
{
printf("%d is bigger\n", a);
}
}
void main()
{
char* StrNum = "1234";
p FuncP; //creat a function pointer
FuncP = StrToInt; //point to converting function
IntCompare(FuncP, StrNum, 21);
}
What I'm asking is:
Could somebody give me a similar example about how to use typedef void (CALLBACK *name)(int,int);? Please help me understand when and how to use it. Thank you for your attention.

CALLBACK is macro. It relates to callback functions but it's not the same. You can start looking at implementation of callback functions in C.
qsort for example uses this technique. qsort is a single function which can sort any array. But you have to tell qsort how to compare different data types. That's done by passing a function pointer to qsort.
int compare_int(const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int compare_string(const void * a, const void * b)
{
const char *pa = *(const char**)a;
const char *pb = *(const char**)b;
return strcmp(pa, pb);
}
int main ()
{
int int_array[] = { 3, 2, 1 };
int count = sizeof(int_array) / sizeof(int);
qsort(int_array, count, sizeof(int), compare_int);
const char *string_array[] = { "234","123","456" };
count = sizeof(string_array) / sizeof(char*);
qsort(string_array, count, sizeof(char*), compare_string);
return 0;
}
Of course in C++ we use std::sort, which uses templates instead.
But we still need to pass functions in C++. See for example, the implementation of for_each
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
for (; first != last; ++first) {
f(*first);
}
return f;
}
Usage:
std::vector<int> nums{ 3, 4, 2, 8, 15, 267 };
auto print = [](const int& n) { std::cout << " " << n; };
std::for_each(nums.begin(), nums.end(), print);
std::cout << '\n';

Related

Overload operator[] with different return Type [duplicate]

We all know that you can overload a function according to the parameters:
int mul(int i, int j) { return i*j; }
std::string mul(char c, int n) { return std::string(n, c); }
Can you overload a function according to the return value? Define a function that returns different things according to how the return value is used:
int n = mul(6, 3); // n = 18
std::string s = mul(6, 3); // s = "666"
// Note that both invocations take the exact same parameters (same types)
You can assume the first parameter is between 0-9, no need to verify the input or have any error handling.
You have to tell the compiler which version to use. In C++, you can do it three ways.
Explicitly differentiate the calls by typing
You somewhat cheated because you sent an integer to a function waiting for a char, and wrongly sent the number six when the char value of '6' is not 6 but 54 (in ASCII):
std::string mul(char c, int n) { return std::string(n, c); }
std::string s = mul(6, 3); // s = "666"
The right solution would be, of course,
std::string s = mul(static_cast<char>(54), 3); // s = "666"
This was worth mentioning, I guess, even if you did not want the solution.
Explicitly differentiate the calls by dummy pointer
You can add a dummy parameter to each functions, thus forcing the compiler to choose the right functions. The easiest way is to send a NULL dummy pointer of the type desired for the return:
int mul(int *, int i, int j) { return i*j; }
std::string mul(std::string *, char c, int n) { return std::string(n, c); }
Which can be used with the code:
int n = mul((int *) NULL, 6, 3); // n = 18
std::string s = mul((std::string *) NULL, 54, 3); // s = "666"
Explicitly differentiate the calls by templating the return value
With this solution, we create a "dummy" function with code that won't compile if instantiated:
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
You'll note this function won't compile, which is a good thing because we want only to use some limited functions through template specialization:
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
template<>
std::string mul<std::string>(int i, int j)
{
return std::string(j, static_cast<char>(i)) ;
}
Thus, the following code will compile:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(54, 3); // s = "666"
But this one won't:
short n2 = mul<short>(6, 3); // error: assignment of read-only variable ‘k’
Explicitly differentiate the calls by templating the return value, 2
Hey, you cheated, too!
Right, I did use the same parameters for the two "overloaded" functions. But you did start the cheating (see above)...
^_^
More seriously, if you need to have different parameters, then you will to write more code, and then have to explicitly use the right types when calling the functions to avoid ambiguities:
// For "int, int" calls
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
// For "char, int" calls
template<typename T>
T mul(char i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
std::string mul<std::string>(char i, int j)
{
return std::string(j, (char) i) ;
}
And this code would be used as such:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>('6', 3); // s = "666"
And the following line:
short n2 = mul<short>(6, 3); // n = 18
Would still not compile.
Conclusion
I love C++...
:-p
class mul
{
public:
mul(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
Not that I would use that.
If you wanted to make mul be a real function instead of a class, you could just use an intermediate class:
class StringOrInt
{
public:
StringOrInt(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
StringOrInt mul(int p1, int p2)
{
return StringOrInt(p1, p2);
}
This lets you do things like passing mul as a function into std algorithms:
int main(int argc, char* argv[])
{
vector<int> x;
x.push_back(3);
x.push_back(4);
x.push_back(5);
x.push_back(6);
vector<int> intDest(x.size());
transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 15 20 25 30
for (vector<int>::const_iterator i = intDest.begin(); i != intDest.end(); ++i)
cout << *i << " ";
cout << endl;
vector<string> stringDest(x.size());
transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 555 5555 55555 555555
for (vector<string>::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}
No.
You can't overload by return value because the caller can do anything (or nothing) with it. Consider:
mul(1, 2);
The return value is just thrown away, so there's no way it could choose an overload based on return value alone.
Use implicit conversion in an in between class.
class BadIdea
{
public:
operator string() { return "silly"; }
operator int() { return 15; }
};
BadIdea mul(int, int)
You get the idea, terrible idea though.
Let mul be a class, mul(x, y) its constructor, and overload some casting operators.
You cannot overload a function based on the return value only.
However, while strictly speaking this is not an overloaded function, you could return from your function as a result an instance of a class that overloads the conversion operators.
I presume you could have it return some weird type Foo that just captures the parameters and then Foo has an implicit operator int and operator string, and it would "work", though it wouldn't really be overloading, rather an implicit conversion trick.
Short and simple, the answer is NO. In C++ the requirements are:
1: name of functions MUST be the same
2: set of arguments MUST differ
*The return type can be the same or different
//This is not valid
int foo();
float foo();
typedef int Int;
int foo(int j);
int foo(Int j);
//Valid:
int foo(int j);
char* foo(char * s);
int foo(int j, int k);
float foo(int j, float k);
float foo(float j, float k);
As far as I know, you can't (big pity, though...). As a workaround, you can define an 'out' parameter instead, and overload that one.
Not in C++. What you'd get in the above example would be the returned value which is an int cast into something string can understand, most likely a char. Which would be ASCII 18 or "device control 2".
You can use the functor solution above. C++ does not support this for functions except for const. You can overload based on const.
You could use a template, but then you'd have to specify the template parameter when you make the call.
Put it in a different namespace? That would be how I would do it. Not strictly an overload, rather a just having two methods with the same name, but a different scope (hence the :: scope resolution operator).
So stringnamespace::mul and intnamespace::mul. Maybe its not really what you are asking, but it seems like the only way to do it.
You could do something like
template<typename T>
T mul(int i,int j){
return i * j;
}
template<>
std::string mul(int i,int j){
return std::string(j,i);
}
And then call it like this:
int x = mul<int>(2,3);
std::string s = mul<std::string>(2,3);
There is no way of overloading on the return value.
OK you geniuses ;) this is how you do it like a pro.
class mul
{
int m_i,m_j;
public:
mull(int i,int j):m_i(i),m_j(j){}
template
operator R()
{
return (R)m_i * m_j;
}
};
use like
double d = mul(1,2);
long l = mul(1,2);
no stupid <>

Function expecting arguments and returning a pointer to a void function

I have several void-functions that do some important things in my code.
void function1(Myclass class1, int myvar)
{
// do some stuff
}
void function2(Myclass class1, int myvar)
{
// do some other stuff
}
// ... maybe some more similar functions
I want to create a function that would return a pointer to any of these functions depending on arguments I pass. I don't know how to do it. I want to have something like
void* choosefunction(int i, int j)
{
if (i == j) return (void*)function1;
else return (void *)function2;
}
Then I would just call them by this pointer.
void *(*ptrProcFunc)(int,int);
ptrProcFunc = &choosefunction;
(*ptrr)() = ptrProcFunc(i,j);
ptrr(class1,myvar);
How to do it correctly? Thank you.
typedef is your friend.
typedef void (*func_ptr)(Myclass, int);
func_ptr choosefunction(int i, int j)
{
if (i == j) return &function1;
else return &function2;
}
Then:
func_ptr ptrr = choosefunction(i,j);
ptrr(class1,myvar);
Here is a complete example.
#include <functional>
#include <iostream>
// Typedef for convenience, called "fcn".
typedef void(*fcn)(int, int);
// You could also use c++11's std::function, which is easier
// to read than function pointers.
typedef std::function<void(int, int)> modern_fcn;
void func1(int a, int b) {
std::cout << "func1" << std::endl;
}
void func2(int a, int b) {
std::cout << "func2" << std::endl;
}
// This returns our typedef'd function pointer.
fcn pick(int i, int j) {
if (i == j) {
return &func1;
} else {
return &func2;
}
}
int main()
{
// Should call func1.
pick(1,1)(3, 5);
// Should call func2.
pick(1,2)(3, 5);
}
You have several options:
You can use an using declaration to introduce an alias for your type:
using func_ptr = void (*)(Myclass, int);
using choose_ptr = void *(*)(int,int);
// ...
func_ptr choosefunction(int i, int j) {
if (i == j) return &function1;
else return &function2;
}
// ...
choose_ptr ptrProcFunc = &choosefunction;
func_ptr ptrr = ptrProcFunc(i,j);
ptrr(class1,myvar);
You can use the auto specifier and that's all (C++14):
auto choosefunction(int i, int j) {
if (i == j) return &function1;
else return &function2;
}
// ...
auto ptrProcFunc = &choosefunction;
auto ptrr = ptrProcFunc(i,j);
ptrr(class1,myvar);
You can use the auto specifier and the trailing type (C++11):
auto choosefunction(int i, int j) -> decltype(&function1) {
if (i == j) return &function1;
else return &function2;
}
// ...
auto ptrProcFunc = &choosefunction;
auto ptrr = ptrProcFunc(i,j);
ptrr(class1,myvar);
In this case, we exploit the fact that function1 and function2 have the same type.
Your confusion (and I've seen this in a lot of people learning C or C++)) is that those are not "void functions". At best you can say they are functions not returning anything (and if you are a bit more relaxed and abuse the language we can say they are functions returning void). They are functions receiving a Myclass and an int arguments and returning nothing.
The other answers show you how you can accomplish that. I strongly encourage you to use using instead of typedef, especially for a function type:
using func_ptr = void (*)(Myclass, int);
The source of the confusion (I think) is that you first learn variable declarations:
int a
and you learn that the type of the declared entity is named on it's left.
Then you learn functions and you write:
int sum(int a, int b)
And by (wrong) analogy you say: the entity being declared is sum so it's type must be what is written on it's left, i.e. int. So you say "sum is of type int" which is wrong and induces confusions like the one in you OP.
The type of sum is "function receiving two integers as parameters and returning an integer".
To help you shed your habit, write or at least think of functions in the new trailing return type declaration syntax:
auto sum(int a, int b) -> int
The (ugly) syntax is
void (*choosefunction(int i, int j))(Myclass, int)
{
if (i == j) return &function1;
else return &function2;
}
With using (or typedef), it becomes readable:
using F = void(Myclass, int);
using FPtr = void(*)(Myclass, int); // or using FPtr = F*;
And then
F* choosefunction(int i, int j);
or
FPtr choosefunction(int i, int j);
if you inline definition, you may in c++14 use simpler auto:
auto choosefunction(int i, int j) {
if (i == j) return &function1;
else return &function2;
}
Anyway, usage would be something like:
FPtr f = choosefunction(i, j);
f(myclass, myvar);

How to define pointer to pointer to function and how to use it in C++?

My question is how to translate the following example? Is this a function, that returns int pointer?
int* (*function)(int, (int (*k)(int *)));
And can I can't write program that use it?
Thanks in advance!
It is a function-pointer
The function returns a pointer to an int
The function's first arg is an int
The function's second arg is a function-pointer k
k returns an int
k takes a pointer to an int as argument
Sure you can use that in your program. It is not too unusual. There are much worse declarations i have seen.
I renamed your "function" to "F" for clarity. Then you can write:
int* (*F)(int, int (*kFunc)(int *) );
Alternative:
typedef int (*kFunc)(int *);
int* (*F)(int, kFunc);
There are a lot of ways to use pointer to a function, may be a pattern such as Factory could take advantage of the function pointer to create new objects.( Look here : http://www.codeproject.com/Articles/3734/Different-ways-of-implementing-factories)
May be this piece of code could help you and give ideas of how powerfull can be working with function pointers.
#include <stdio.h>
#include <stdlib.h>
#include <map>
// Define the func ptrs
typedef void (*TFunc)(const char *, int);
typedef int (*TFunc2)(int);
int return_value(int i)
{
return i * 5;
}
void a( const char *name, int i )
{
printf ("a->%s %d\n\n", name, i);
}
void b( const char *name, int i)
{
printf ("b->%s %d\n\n", name, i);
}
struct test
{
const char *name;
int i;
TFunc func;
};
static test test_array[2] =
{
{ "a", 0, a },
{ "b", 1, b },
};
int main(int argc, char **argv, char** envp)
{
// Check the simple case, pointer to a function
TFunc fnc = a;
TFunc2 fnc2 = return_value;
fnc("blabla", 5);
fnc = b;
fnc("hello!", 55);
printf ("%d\n\n",fnc2(5));
//Check arrays of structs when there is a pointer to a fnc
test_array[0].func(test_array[0].name, test_array[0].i);
test_array[1].func(test_array[1].name, test_array[1].i);
//Handle a map of functions( This could be a little implementation of a factory )
typedef std::map<int, TFunc > myMap;
myMap lMap;
lMap.insert(std::make_pair(5, a));
lMap.insert(std::make_pair(2, b));
if( lMap.find( 5 ) != lMap.end() )
{
lMap[5]("hello map 5", 1);
}
myMap::iterator lItFind = lMap.find(2);
if( lItFind != lMap.end() )
{
lItFind->second("hello map 2", 2);
}
return(0);
}
I hope that this helps you.
You should remove extra parentheses, this is correct version:
int* (*function)(int, int (*k)(int *));
explanation (using right-left rule):
int* (*fn)(int, int (*k)(int *));
fn : fn is a
(*fn) : pointer
(*fn)(int, int (*k)(int *)) : to a function taking as arguments
- an int and
- function pointer
which takes a pointer to int
and returns int
int* (*fn)(int, int (*k)(int *)) : and returns a pointer to int
below is a short example on how to use it, also you ask for How to define pointer to pointer to function so below this is also included.
http://coliru.stacked-crooked.com/a/d05200cf5f6397b8
#include <iostream>
int bar(int*) {
std::cout << "inside bar\n";
return 0;
}
int* foo(int, int (*k)(int *)) {
std::cout << "inside foo\n";
k(nullptr);
return nullptr;
}
int main() {
int* (*function)(int, int (*k)(int *));
function = foo;
function(0, bar);
// Now, as you asked for, a pointer to pointer to above function
decltype(function) *pff;
pff = &function;
(*pff)(0, bar);
}

c++ Does the return type of a function cause ambiguity? [duplicate]

We all know that you can overload a function according to the parameters:
int mul(int i, int j) { return i*j; }
std::string mul(char c, int n) { return std::string(n, c); }
Can you overload a function according to the return value? Define a function that returns different things according to how the return value is used:
int n = mul(6, 3); // n = 18
std::string s = mul(6, 3); // s = "666"
// Note that both invocations take the exact same parameters (same types)
You can assume the first parameter is between 0-9, no need to verify the input or have any error handling.
You have to tell the compiler which version to use. In C++, you can do it three ways.
Explicitly differentiate the calls by typing
You somewhat cheated because you sent an integer to a function waiting for a char, and wrongly sent the number six when the char value of '6' is not 6 but 54 (in ASCII):
std::string mul(char c, int n) { return std::string(n, c); }
std::string s = mul(6, 3); // s = "666"
The right solution would be, of course,
std::string s = mul(static_cast<char>(54), 3); // s = "666"
This was worth mentioning, I guess, even if you did not want the solution.
Explicitly differentiate the calls by dummy pointer
You can add a dummy parameter to each functions, thus forcing the compiler to choose the right functions. The easiest way is to send a NULL dummy pointer of the type desired for the return:
int mul(int *, int i, int j) { return i*j; }
std::string mul(std::string *, char c, int n) { return std::string(n, c); }
Which can be used with the code:
int n = mul((int *) NULL, 6, 3); // n = 18
std::string s = mul((std::string *) NULL, 54, 3); // s = "666"
Explicitly differentiate the calls by templating the return value
With this solution, we create a "dummy" function with code that won't compile if instantiated:
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
You'll note this function won't compile, which is a good thing because we want only to use some limited functions through template specialization:
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
template<>
std::string mul<std::string>(int i, int j)
{
return std::string(j, static_cast<char>(i)) ;
}
Thus, the following code will compile:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(54, 3); // s = "666"
But this one won't:
short n2 = mul<short>(6, 3); // error: assignment of read-only variable ‘k’
Explicitly differentiate the calls by templating the return value, 2
Hey, you cheated, too!
Right, I did use the same parameters for the two "overloaded" functions. But you did start the cheating (see above)...
^_^
More seriously, if you need to have different parameters, then you will to write more code, and then have to explicitly use the right types when calling the functions to avoid ambiguities:
// For "int, int" calls
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
// For "char, int" calls
template<typename T>
T mul(char i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
std::string mul<std::string>(char i, int j)
{
return std::string(j, (char) i) ;
}
And this code would be used as such:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>('6', 3); // s = "666"
And the following line:
short n2 = mul<short>(6, 3); // n = 18
Would still not compile.
Conclusion
I love C++...
:-p
class mul
{
public:
mul(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
Not that I would use that.
If you wanted to make mul be a real function instead of a class, you could just use an intermediate class:
class StringOrInt
{
public:
StringOrInt(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
StringOrInt mul(int p1, int p2)
{
return StringOrInt(p1, p2);
}
This lets you do things like passing mul as a function into std algorithms:
int main(int argc, char* argv[])
{
vector<int> x;
x.push_back(3);
x.push_back(4);
x.push_back(5);
x.push_back(6);
vector<int> intDest(x.size());
transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 15 20 25 30
for (vector<int>::const_iterator i = intDest.begin(); i != intDest.end(); ++i)
cout << *i << " ";
cout << endl;
vector<string> stringDest(x.size());
transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 555 5555 55555 555555
for (vector<string>::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}
No.
You can't overload by return value because the caller can do anything (or nothing) with it. Consider:
mul(1, 2);
The return value is just thrown away, so there's no way it could choose an overload based on return value alone.
Use implicit conversion in an in between class.
class BadIdea
{
public:
operator string() { return "silly"; }
operator int() { return 15; }
};
BadIdea mul(int, int)
You get the idea, terrible idea though.
Let mul be a class, mul(x, y) its constructor, and overload some casting operators.
You cannot overload a function based on the return value only.
However, while strictly speaking this is not an overloaded function, you could return from your function as a result an instance of a class that overloads the conversion operators.
I presume you could have it return some weird type Foo that just captures the parameters and then Foo has an implicit operator int and operator string, and it would "work", though it wouldn't really be overloading, rather an implicit conversion trick.
Short and simple, the answer is NO. In C++ the requirements are:
1: name of functions MUST be the same
2: set of arguments MUST differ
*The return type can be the same or different
//This is not valid
int foo();
float foo();
typedef int Int;
int foo(int j);
int foo(Int j);
//Valid:
int foo(int j);
char* foo(char * s);
int foo(int j, int k);
float foo(int j, float k);
float foo(float j, float k);
As far as I know, you can't (big pity, though...). As a workaround, you can define an 'out' parameter instead, and overload that one.
Not in C++. What you'd get in the above example would be the returned value which is an int cast into something string can understand, most likely a char. Which would be ASCII 18 or "device control 2".
You can use the functor solution above. C++ does not support this for functions except for const. You can overload based on const.
You could use a template, but then you'd have to specify the template parameter when you make the call.
Put it in a different namespace? That would be how I would do it. Not strictly an overload, rather a just having two methods with the same name, but a different scope (hence the :: scope resolution operator).
So stringnamespace::mul and intnamespace::mul. Maybe its not really what you are asking, but it seems like the only way to do it.
You could do something like
template<typename T>
T mul(int i,int j){
return i * j;
}
template<>
std::string mul(int i,int j){
return std::string(j,i);
}
And then call it like this:
int x = mul<int>(2,3);
std::string s = mul<std::string>(2,3);
There is no way of overloading on the return value.
OK you geniuses ;) this is how you do it like a pro.
class mul
{
int m_i,m_j;
public:
mull(int i,int j):m_i(i),m_j(j){}
template
operator R()
{
return (R)m_i * m_j;
}
};
use like
double d = mul(1,2);
long l = mul(1,2);
no stupid <>

Overload a C++ function according to the return value

We all know that you can overload a function according to the parameters:
int mul(int i, int j) { return i*j; }
std::string mul(char c, int n) { return std::string(n, c); }
Can you overload a function according to the return value? Define a function that returns different things according to how the return value is used:
int n = mul(6, 3); // n = 18
std::string s = mul(6, 3); // s = "666"
// Note that both invocations take the exact same parameters (same types)
You can assume the first parameter is between 0-9, no need to verify the input or have any error handling.
You have to tell the compiler which version to use. In C++, you can do it three ways.
Explicitly differentiate the calls by typing
You somewhat cheated because you sent an integer to a function waiting for a char, and wrongly sent the number six when the char value of '6' is not 6 but 54 (in ASCII):
std::string mul(char c, int n) { return std::string(n, c); }
std::string s = mul(6, 3); // s = "666"
The right solution would be, of course,
std::string s = mul(static_cast<char>(54), 3); // s = "666"
This was worth mentioning, I guess, even if you did not want the solution.
Explicitly differentiate the calls by dummy pointer
You can add a dummy parameter to each functions, thus forcing the compiler to choose the right functions. The easiest way is to send a NULL dummy pointer of the type desired for the return:
int mul(int *, int i, int j) { return i*j; }
std::string mul(std::string *, char c, int n) { return std::string(n, c); }
Which can be used with the code:
int n = mul((int *) NULL, 6, 3); // n = 18
std::string s = mul((std::string *) NULL, 54, 3); // s = "666"
Explicitly differentiate the calls by templating the return value
With this solution, we create a "dummy" function with code that won't compile if instantiated:
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
You'll note this function won't compile, which is a good thing because we want only to use some limited functions through template specialization:
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
template<>
std::string mul<std::string>(int i, int j)
{
return std::string(j, static_cast<char>(i)) ;
}
Thus, the following code will compile:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(54, 3); // s = "666"
But this one won't:
short n2 = mul<short>(6, 3); // error: assignment of read-only variable ‘k’
Explicitly differentiate the calls by templating the return value, 2
Hey, you cheated, too!
Right, I did use the same parameters for the two "overloaded" functions. But you did start the cheating (see above)...
^_^
More seriously, if you need to have different parameters, then you will to write more code, and then have to explicitly use the right types when calling the functions to avoid ambiguities:
// For "int, int" calls
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
// For "char, int" calls
template<typename T>
T mul(char i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
std::string mul<std::string>(char i, int j)
{
return std::string(j, (char) i) ;
}
And this code would be used as such:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>('6', 3); // s = "666"
And the following line:
short n2 = mul<short>(6, 3); // n = 18
Would still not compile.
Conclusion
I love C++...
:-p
class mul
{
public:
mul(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
Not that I would use that.
If you wanted to make mul be a real function instead of a class, you could just use an intermediate class:
class StringOrInt
{
public:
StringOrInt(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
StringOrInt mul(int p1, int p2)
{
return StringOrInt(p1, p2);
}
This lets you do things like passing mul as a function into std algorithms:
int main(int argc, char* argv[])
{
vector<int> x;
x.push_back(3);
x.push_back(4);
x.push_back(5);
x.push_back(6);
vector<int> intDest(x.size());
transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 15 20 25 30
for (vector<int>::const_iterator i = intDest.begin(); i != intDest.end(); ++i)
cout << *i << " ";
cout << endl;
vector<string> stringDest(x.size());
transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 555 5555 55555 555555
for (vector<string>::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}
No.
You can't overload by return value because the caller can do anything (or nothing) with it. Consider:
mul(1, 2);
The return value is just thrown away, so there's no way it could choose an overload based on return value alone.
Use implicit conversion in an in between class.
class BadIdea
{
public:
operator string() { return "silly"; }
operator int() { return 15; }
};
BadIdea mul(int, int)
You get the idea, terrible idea though.
Let mul be a class, mul(x, y) its constructor, and overload some casting operators.
You cannot overload a function based on the return value only.
However, while strictly speaking this is not an overloaded function, you could return from your function as a result an instance of a class that overloads the conversion operators.
I presume you could have it return some weird type Foo that just captures the parameters and then Foo has an implicit operator int and operator string, and it would "work", though it wouldn't really be overloading, rather an implicit conversion trick.
Short and simple, the answer is NO. In C++ the requirements are:
1: name of functions MUST be the same
2: set of arguments MUST differ
*The return type can be the same or different
//This is not valid
int foo();
float foo();
typedef int Int;
int foo(int j);
int foo(Int j);
//Valid:
int foo(int j);
char* foo(char * s);
int foo(int j, int k);
float foo(int j, float k);
float foo(float j, float k);
As far as I know, you can't (big pity, though...). As a workaround, you can define an 'out' parameter instead, and overload that one.
Not in C++. What you'd get in the above example would be the returned value which is an int cast into something string can understand, most likely a char. Which would be ASCII 18 or "device control 2".
You can use the functor solution above. C++ does not support this for functions except for const. You can overload based on const.
You could use a template, but then you'd have to specify the template parameter when you make the call.
Put it in a different namespace? That would be how I would do it. Not strictly an overload, rather a just having two methods with the same name, but a different scope (hence the :: scope resolution operator).
So stringnamespace::mul and intnamespace::mul. Maybe its not really what you are asking, but it seems like the only way to do it.
You could do something like
template<typename T>
T mul(int i,int j){
return i * j;
}
template<>
std::string mul(int i,int j){
return std::string(j,i);
}
And then call it like this:
int x = mul<int>(2,3);
std::string s = mul<std::string>(2,3);
There is no way of overloading on the return value.
OK you geniuses ;) this is how you do it like a pro.
class mul
{
int m_i,m_j;
public:
mull(int i,int j):m_i(i),m_j(j){}
template
operator R()
{
return (R)m_i * m_j;
}
};
use like
double d = mul(1,2);
long l = mul(1,2);
no stupid <>