Related
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 <>
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 <>
I've got a class with 3 private variables and one public method, that has 2 char parameter variables.
class InitLine
{
private:
char *a;
char b, c;
public:
InitLine(char *inita, char initc);
Init(char *a, char c);
};
Now the definition of the method is simple:
Initline::Init(char *a, char c)
{
for (b=0; b<c; b++)
*(a+c)=0;
}
Now my question is: If I wish to repeat the same actions with different parametertypes (*a and c, or one of them becomes an integer e.g.), is it necessary to create a new class, or can I use the existing one, doing some 'typecasting' or some other trick I don't know yet?
Thanks and regards
Uwe
Use templates, make the Init function a template of your arguments type.
template <typename T>
Init(char*a , T c){}
for instance
You have many places in your code, which should be fixed prior to any further operations.
Naming convention is terrible. What is a, b, c?
You use b as a loop indexer, while a local variable should be used there instead.
You don't show us, what is a. Where is it allocated? What is the size of memory pointed to by a?
I guess, that your code should look like the following:
class InitLine
{
private:
char * data;
int count;
public:
InitLine(char * newData, int newCount)
{
// Possible error checking?
data = newData;
count = newCount;
}
// No parameters needed here, I guess
void Init()
{
for (int i = 0; i < count; i++)
data[i] = 0;
}
};
As for your question, I'm not really sure, what you are trying to achieve and what do you want to know. If you want to write a generic class holding any type of arrays, you have to use templates:
template <typename T>
class InitLine
{
private:
T * data;
int count;
public:
InitLine(T * newData, int newCount)
{
// Possible error checking?
data = newData;
count = newCount;
}
// No parameters needed here, I guess
void Init()
{
for (int i = 0; i < count; i++)
data[i] = 0;
}
};
You have to use this class in the following way:
InitLine<char> line(myData, myDataSize);
// where myData is a char * and myDataSize is an int
If you want to write a few methods differing by their parameters, this technique is called method overloading and is available in C++:
void Init(char * a, int b) { /* sth */ }
void Init(int * a, int b) { /* sth */ }
Note, that compiler must be able to clearly distinguish, which method should be called. Eg.
void Test(int a) { }
void Test(char a) { }
Test(0); // Ambiguity: which method should be called?
These are only things coming to my mind, while reading your question. If it is not what you are asking for, consider editing the question to be more specific.
If you just want to have the whole class with different types (not just the Init), e.g. also have int *a; int b,c; then template classes are the other trick you don't know yet.
template <typename ANYTYPE> class InitLine
{
private:
ANYTYPE *a;
ANYTYPE b, c;
public:
void InitLine(ANYTYPE *inita, ANYTYPE initc);
void Init(ANYTYPE *a, ANYTYPE c);
};
template <typename ANYTYPE> void Initline<ANYTYPE>::Init(ANYTYPE *a, ANYTYPE c)
{
for (int b=0; b<c; b++)
*(a+c)=0;
}
... main()
{
Initline<int> iline; // initline class based on type int (ANYTYPE -> int)
int line[20];
Initline<char> cline; // initline class based on type char (ANYTYPE -> char)
char somechars[30];
iline.Init(line, 20);
cline.Init(somechars, 30);
Okay, I have posted a few questions lately related to wrapping a C callback API with a C++11-ish interface. I have almost got a satisfying solution, but I think it could be more elegant and need the help of some template metaprogramming wizards :)
Bear with me, as the example code is a little long, but I've tried to demonstrate the problem in one shot. Basically, the idea is that, given a list of function pointers and data context pointers, I want to provide a callback mechanism that can be provided with,
Function pointers
Function objects (functors)
Lambdas
Moreover, I want to make these functions callable by a variety of prototypes. What I mean is, the C API provides about 7 different parameters to the callback, but in most cases the user code is really only interested in one or two of these. So I'd like the user to be able to specify only the arguments he is interested in. (This extends from the point of allowing lambdas in the first place... to allow conciseness.)
In this example, the nominal C callback takes an int and a float parameter, and an optional float* which can be used to return some extra data. So the intention of the C++ code is to be able to provide a callback of any of these prototypes, in any form that is "callable". (e.g. functor, lambda, etc.)
int callback2args(int a, float b);
int callback3args(int a, float b, float *c);
Here is my solution so far.
#include <cstdio>
#include <vector>
#include <functional>
typedef int call2args(int,float);
typedef int call3args(int,float,float*);
typedef std::function<call2args> fcall2args;
typedef std::function<call3args> fcall3args;
typedef int callback(int,float,float*,void*);
typedef std::pair<callback*,void*> cb;
std::vector<cb> callbacks;
template <typename H>
static
int call(int a, float b, float *c, void *user);
template <>
int call<call2args>(int a, float b, float *c, void *user)
{
call2args *h = (call2args*)user;
return (*h)(a, b);
}
template <>
int call<call3args>(int a, float b, float *c, void *user)
{
call3args *h = (call3args*)user;
return (*h)(a, b, c);
}
template <>
int call<fcall2args>(int a, float b, float *c, void *user)
{
fcall2args *h = (fcall2args*)user;
return (*h)(a, b);
}
template <>
int call<fcall3args>(int a, float b, float *c, void *user)
{
fcall3args *h = (fcall3args*)user;
return (*h)(a, b, c);
}
template<typename H>
void add_callback(const H &h)
{
H *j = new H(h);
callbacks.push_back(cb(call<H>, (void*)j));
}
template<>
void add_callback<call2args>(const call2args &h)
{
callbacks.push_back(cb(call<call2args>, (void*)h));
}
template<>
void add_callback<call3args>(const call3args &h)
{
callbacks.push_back(cb(call<call3args>, (void*)h));
}
template<>
void add_callback<fcall2args>(const fcall2args &h)
{
fcall2args *j = new fcall2args(h);
callbacks.push_back(cb(call<fcall2args>, (void*)j));
}
template<>
void add_callback<fcall3args>(const fcall3args &h)
{
fcall3args *j = new fcall3args(h);
callbacks.push_back(cb(call<fcall3args>, (void*)j));
}
// Regular C-style callback functions (context-free)
int test1(int a, float b)
{
printf("test1 -- a: %d, b: %f", a, b);
return a*b;
}
int test2(int a, float b, float *c)
{
printf("test2 -- a: %d, b: %f", a, b);
*c = a*b;
return a*b;
}
void init()
{
// A functor class
class test3
{
public:
test3(int j) : _j(j) {};
int operator () (int a, float b)
{
printf("test3 -- a: %d, b: %f", a, b);
return a*b*_j;
}
private:
int _j;
};
// Regular function pointer of 2 parameters
add_callback(test1);
// Regular function pointer of 3 parameters
add_callback(test2);
// Some lambda context!
int j = 5;
// Wrap a 2-parameter functor in std::function
add_callback(fcall2args(test3(j)));
// Wrap a 2-parameter lambda in std::function
add_callback(fcall2args([j](int a, float b)
{
printf("test4 -- a: %d, b: %f", a, b);
return a*b*j;
}));
// Wrap a 3-parameter lambda in std::function
add_callback(fcall3args([j](int a, float b, float *c)
{
printf("test5 -- a: %d, b: %f", a, b);
*c = a*b*j;
return a*b*j;
}));
}
int main()
{
init();
auto c = callbacks.begin();
while (c!=callbacks.end()) {
float d=0;
int r = c->first(2,3,&d,c->second);
printf(" result: %d (%f)\n", r, d);
c ++;
}
}
Okay, as you can see, this actually works. However, I find the solution of having to explicitly wrap the functors/lambdas as std::function types kind of inelegant. I really wanted to make the compiler match the function type automatically but this doesn't seem to work. If I remove the 3-parameter variant, then the fcall2args wrapper is not needed, however the presence of the fcall3args version of add_callback makes it apparently ambiguous to the compiler. In other words it seems to not be able to do pattern matching based on the lambda call signature.
A second problem is that I'm of course making copies of the functor/lambda objects using new, but not deleteing this memory. I'm not at the moment sure what the best way will be to track these allocations, although I guess in a real implementation I could track them in an object of which add_callback is a member, and free them in the destructor.
Thirdly, I don't find it very elegant to have specific types call2args, call3args, etc., for each variation of the callback I want to allow. It means I'll need an explosion of types for every combination of parameters the user might need. I was hoping there could be some template solution to make this more generic, but I am having trouble coming up with it.
Edit for explanation: The definition in this code, std::vector<std::pair<callback*,void*>> callbacks, is part of the problem definition, not part of the answer. The problem I am trying to solve is to map C++ objects onto this interface--therefore, proposing better ways to organize this std::vector doesn't solve the problem for me. Thanks. Just to clarify.
Edit #2: Okay, forget the fact that my example code uses std::vector<std::pair<callback*,void*>> callbacks to hold the callbacks. Imagine instead, as this is the actual scenario, that I have some C library implementing the following interface:
struct someobject *create_object();
free_object(struct someobject *obj);
add_object_callback(struct someobject *obj, callback *c, void *context);
where callback is,
typedef int callback(int a,float b,float *c, void *context);
Okay. So "someobject" will experience external events of some kind, network data, or input events, etc., and call its list of callbacks when these happen.
This is a pretty standard implementation of callbacks in C. Importantly, this is an existing library, something for which I cannot change, but I am trying to write a nice, idiomatic C++ wrapper around it. I want my C++ users to be able to add lambdas as callbacks. So, I want to design a C++ interface that allows users to be able to do the following:
add_object_callback(struct someobject *obj, func);
where func is one of the following:
a regular C function that doesn't use context.
a functor object
a lambda
Additionally, in each case, it should be possible for the function/functor/lambda to have either of the following signatures:
int cb2args(int a, float b);
int cb2args(int a, float b, float *c);
I think this should be possible, and I got about 80% of the way there, but I'm stuck on template polymorphism based on the call signature. I don't know offhand whether it's possible. Maybe it needs some voodoo involving function_traits or something, but it's a little beyond my experience. In any case, there are many, many C libraries that use such an interface, and I think it would be great to allow this kind of convenience when using them from C++.
Since you are using the C API in C++11, you could as well just wrap the whole thing in a C++ class. This is also necessary, as you mentioned in the 2nd problem, to solve the resource leak.
Also remember that a lambda expression without capture can be implicitly converted to a function pointer. This could remove all the call<*> because they can be moved into the add_callbacks.
And finally, we could use SFINAE to remove the fcall3args types. Here is the result.
class SomeObject {
// The real object being wrapped.
struct someobject* m_self;
// The vector of callbacks which requires destruction. This vector is only a
// memory store, and serves no purpose otherwise.
typedef std::function<int(int, float, float*)> Callback;
std::vector<std::unique_ptr<Callback>> m_functions;
// Add a callback to the object. Note the capture-less lambda.
template <typename H>
void add_callback_impl(H&& h) {
std::unique_ptr<Callback> callback (new Callback(std::forward<H>(h)));
add_object_callback(m_self, [](int a, float b, float* c, void* raw_ctx) {
return (*static_cast<Callback*>(raw_ctx))(a, b, c);
}, callback.get());
m_functions.push_back(std::move(callback));
}
public:
SomeObject() : m_self(create_object()) {}
~SomeObject() { free_object(m_self); }
// We create 4 public overloads to add_callback:
// This only accepts function objects having 2 arguments.
template <typename H>
auto add_callback(H&& h) -> decltype(h(1, 10.f), void()) {
using namespace std::placeholders;
add_callback_impl(std::bind(std::forward<H>(h), _1, _2));
}
// This only accepts function objects having 3 arguments.
template <typename H>
auto add_callback(H&& h) -> decltype(h(1, 1.0f, (float*)0), void()) {
add_callback_impl(std::forward<H>(h));
}
// This only accepts function pointers.
void add_callback(int(*h)(int, float)) const {
add_object_callback(m_self, [](int a, float b, float* c, void* d) {
return reinterpret_cast<int(*)(int, float)>(d)(a, b);
}, reinterpret_cast<void*>(h));
}
// This only accepts function pointers.
void add_callback(int(*h)(int, float, float*)) const {
add_object_callback(m_self, [](int a, float b, float* c, void* d) {
return reinterpret_cast<int(*)(int, float, float*)>(d)(a, b, c);
}, reinterpret_cast<void*>(h));
}
// Note that the last 2 overloads violates the C++ standard by assuming
// sizeof(void*) == sizeof(func pointer). This is valid in POSIX, though.
struct someobject* get_raw_object() const {
return m_self;
}
};
So the init() becomes:
void init(SomeObject& so) {
// A functor class
class test3 { ... };
so.add_callback(test1);
so.add_callback(test2);
// Some lambda context!
int j = 5;
so.add_callback(test3(j));
so.add_callback([j](int a, float b) -> int {
printf("test4 -- a: %d, b: %f", a, b);
return a*b*j;
});
so.add_callback([j](int a, float b, float *c) -> int {
printf("test5 -- a: %d, b: %f", a, b);
*c = a*b*j;
return a*b*j;
});
}
The full testing code (I'm not putting that to ideone here, because g++ 4.5 doesn't support implicitly converting a lambda to a function pointer, nor the range-based for.)
#include <vector>
#include <functional>
#include <cstdio>
#include <memory>
struct someobject;
struct someobject* create_object(void);
void free_object(struct someobject* obj);
void add_object_callback(struct someobject* obj,
int(*callback)(int, float, float*, void*),
void* context);
class SomeObject {
// The real object being wrapped.
struct someobject* m_self;
// The vector of callbacks which requires destruction. This vector is only a
// memory store, and serves no purpose otherwise.
typedef std::function<int(int, float, float*)> Callback;
std::vector<std::unique_ptr<Callback>> m_functions;
// Add a callback to the object. Note the capture-less lambda.
template <typename H>
void add_callback_impl(H&& h) {
std::unique_ptr<Callback> callback (new Callback(std::forward<H>(h)));
add_object_callback(m_self, [](int a, float b, float* c, void* raw_ctx) {
return (*static_cast<Callback*>(raw_ctx))(a, b, c);
}, callback.get());
m_functions.push_back(std::move(callback));
}
public:
SomeObject() : m_self(create_object()) {}
~SomeObject() { free_object(m_self); }
// We create 4 public overloads to add_callback:
// This only accepts function objects having 2 arguments.
template <typename H>
auto add_callback(H&& h) -> decltype(h(1, 10.f), void()) {
using namespace std::placeholders;
add_callback_impl(std::bind(std::forward<H>(h), _1, _2));
}
// This only accepts function objects having 3 arguments.
template <typename H>
auto add_callback(H&& h) -> decltype(h(1, 1.0f, (float*)0), void()) {
add_callback_impl(std::forward<H>(h));
}
// This only accepts function pointers.
void add_callback(int(*h)(int, float)) const {
add_object_callback(m_self, [](int a, float b, float* c, void* d) {
return reinterpret_cast<int(*)(int, float)>(d)(a, b);
}, reinterpret_cast<void*>(h));
}
// This only accepts function pointers.
void add_callback(int(*h)(int, float, float*)) const {
add_object_callback(m_self, [](int a, float b, float* c, void* d) {
return reinterpret_cast<int(*)(int, float, float*)>(d)(a, b, c);
}, reinterpret_cast<void*>(h));
}
// Note that the last 2 overloads violates the C++ standard by assuming
// sizeof(void*) == sizeof(func pointer). This is required in POSIX, though.
struct someobject* get_raw_object() const {
return m_self;
}
};
//------------------------------------------------------------------------------
int test1(int a, float b) {
printf("test1 -- a: %d, b: %f", a, b);
return a*b;
}
int test2(int a, float b, float *c) {
printf("test2 -- a: %d, b: %f", a, b);
*c = a*b;
return a*b;
}
void init(SomeObject& so) {
// A functor class
class test3
{
public:
test3(int j) : _j(j) {};
int operator () (int a, float b)
{
printf("test3 -- a: %d, b: %f", a, b);
return a*b*_j;
}
private:
int _j;
};
so.add_callback(test1);
so.add_callback(test2);
// Some lambda context!
int j = 5;
so.add_callback(test3(j));
so.add_callback([j](int a, float b) -> int {
printf("test4 -- a: %d, b: %f", a, b);
return a*b*j;
});
so.add_callback([j](int a, float b, float *c) -> int {
printf("test5 -- a: %d, b: %f", a, b);
*c = a*b*j;
return a*b*j;
});
}
//------------------------------------------------------------------------------
struct someobject {
std::vector<std::pair<int(*)(int,float,float*,void*),void*>> m_callbacks;
void call() const {
for (auto&& cb : m_callbacks) {
float d=0;
int r = cb.first(2, 3, &d, cb.second);
printf(" result: %d (%f)\n", r, d);
}
}
};
struct someobject* create_object(void) {
return new someobject;
}
void free_object(struct someobject* obj) {
delete obj;
}
void add_object_callback(struct someobject* obj,
int(*callback)(int, float, float*, void*),
void* context) {
obj->m_callbacks.emplace_back(callback, context);
}
//------------------------------------------------------------------------------
int main() {
SomeObject so;
init(so);
so.get_raw_object()->call();
}
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 <>