C++ function call - c++

Imagine function func that needs var during run time. Is it possible under c++ to call func without var as a parameter? That is, to have something like this
func(var, i) = func(i);
I would like to do so for the sake of simple readability. Inside my class I could set var as a global parameter and then call only func(i) but this would give troubles if I was going to use threads...
But note that func uses var during run time. Ex:
int func(int var , int i){
return i+var;
}
In fact I will have multiple calls of func(), but all thes calls share the same var. Ex: instead of
int var=2;
int res= func(var, 0) + func(var, 1) +..... func(var, n);
I would write more concisely (in it is the same var)
int var=2;
int res= func(0) + func(1) +..... func(n);

You can do this using lambdas:
auto bound_func = [var](auto i) { return func(var, i); }
Or you can have more freedom by just storing the var in a struct:
struct func_binder
{
var v_;
func_binder(var v)
: v_(v)
{ }
decltype(func(v_, i)) operator()(int i)
{
return func(v_, i);
}
};
This can be used like:
func_binder f(some_var);
f(some_i);
If var is isn't mutated by the function, then you don't need to worry about it with threads. If it is, then it should be wrapped in a structure that that synchronizes access to it somehow.

How about?:
auto func_binded = std::bind( func, var, std::placeholders::_1 );

Add a new function with the same name that takes the parameter i. This function can call the other function with
The correct var. This is called function overloading.
func(i){
func(global_var, i);
}

When declaring your function, you can specifiy a default argument. In your case it has to be the last parameter of your function.
void func(int i, int var=0);
then call it like that func(i);
which is func(i, 0);

yes you can use a default value for you var variable
declare the prototype like this:
fun(type_of_i i,typeofvar var=default_value);
try to use the most relevant value for the default value
Of course you must be able to permute the order of parameters, otherwise use the function overloading mechanism as said in a previous answer
regards

So, you have at least two solutions, the first one is simple to add to a class :
Use variadic template to build a wrapper function (my preferred solution in your case, easy to add to a class). This solution allows you to write int r = newfunc(var, 1, 2, 3); instead of repeating again and again function name :
int funcvar(int var)
{
return 0;
}
template<typename TFirst, typename ... T>
int funcvar(int var, TFirst first, T ... args)
{
return func(var, first) + funcvar(var, args...);
}
Use lambda (a little be difficult to add to a class, because you need a variable of type like std::function<int(int)> fvl and initialized in constructor or pass it by argument):
auto fvl = [var](int i) { return func(var, i); };
examples :
int main()
{
int var = 1;
// Use of variadic template
int result1 = funcvar(var, 1, 2, 3, 4, 5);
int result2 = funcvar(var, 5, 6);
// Use of lambda
auto fvl = [var](int i) { return func(var, i); };
int result3 = fvl(1) + fvl(2) + fvl(3) + fvl(4) + fvl(5);
int result4 = fvl(5) + fvl(6);
std::cout << result1 << std::endl;
std::cout << result2 << std::endl;
std::cout << result3 << std::endl;
std::cout << result4 << std::endl;
}
see here

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 <>

How can a lambda capture itself for an asynchronous call?

I have to make an asynchronous call inside a lambda, and once the asynchronous call is terminated I have to call the lambda itself.
I try to explain my problem with code:
typedef function<void(int id)> Callback;
AsyncWork1(Callback call, int id, string)
{
//...
call(id);
}
AsyncWork2(Callback call, int id, double, string)
{
//...
call(id);
}
void AsyncWorks(Callback final_callback, int id)
{
Callback lambda = [&lambda, final_callback, id](int next_work) -> void
{
if(next_work == 1)
{
//...
AsyncWork1(lambda, 2, "bla bla");
}
else if(next_work == 2)
{
//...
//the lambda variable no longer exists
AsyncWork2(lambda, 3, 0.0, "bla bla");
}
else if(next_work == 3)
{
//...
final_callback(id);
}
};
lambda(1);
}
int main()
{
AsyncWorks(...);
AsyncWorks(...);
AsyncWorks(...);
AsyncWorks(...);
return 0;
}
The problem is that when the code exits from "AsyncWorks(...)" function, the local variable "lambda" no longer exists.
I've read several threads that talk about lambda recursive, but I haven't found any solution.
How can I solve this problem?
The basic problem is that C++ doesn't expose the this pointer of a lambda to itself.
As it happens, there are many languages where during something's definition, you cannot refer to itself. This is fixed in functional languages using a technique called the "Y Combinator".
A simple y combinator in C++ looks like:
template<class F>
struct y_combinator_t {
F f;
template<class...Args>
auto operator()(Args&&...args)
-> std::result_of_t< F&( y_combinator_t<F>&, Args&&... ) >
{
return f( *this, std::forward<Args>(args)... );
}
};
template<class F>
y_combinator_t<std::decay_t<F>> y_combinate( F&& f ) {
return {std::forward<F>(f)};
}
I'm of two minds if we should f( *this or f( f, I sometimes do either.
Use:
void AsyncWorks(Callback final_callback, int id)
{
Callback lambda = y_combinate(
[final_callback, id]
(auto& self, int next_work)
-> void
{
if(next_work == 1) {
//...
AsyncWork1(self, 2, "bla bla");
} else if(next_work == 2) {
//...
//the lambda variable no longer exists
AsyncWork2(self, 3, 0.0, "bla bla");
} else if(next_work == 3) {
//...
final_callback(id);
}
}
);
lambda(1);
}
basically, I added an implicit self parameter to the lambda function body. Caller of the operator() don't see this parameter.
Y combinator based off this post by myself with modifications.
Lambda can capture itself implicitly. To demo how? see below code it calculate factorial value.
#include <iostream>
int (* factorial)( const int) = []( const int number)
{
if( number > 1)
{
return number* factorial( number - 1);
}
else
{
return 1;
}
};
int main(int , char *[])
{
int fact = factorial( 7);
std::cout<< "7! = "<< fact<< std::endl;
}
Output 7! = 5040
If any variable is used inside lambda then lambda captures it implicitly, if it is not captured explicitly. Due to this inside lambda, name factorial referring itself, is available.
But if in place ofint (* factorial)( const int) = []( const int number){//implementation }; if auto is used like as follows,auto factorial = []( const int number){ //implementation };then g++ compiler gives following error,error: use of ‘factorial’ before deduction of ‘auto’
return number* factorial( number - 1);It is because type of factorial is not deduced, auto does not deduce for same control block. Name factorial will be available only below the declaration in case of auto.
#Yakk
To understand your answer I had to spend some time studying many c++ features, value category, rvalue, lvalue, move constructor, move assignment operator, variadic templates, variadic templates with implicit conversions, result_of_t<>, decay_t<>, forward<>.
But I don't have a thing yet, why did you put the '&' symbol here?
... std::result_of_t <F&(y_combinator_t<...
I also rewrote your solution to make it more specific for my case and easier to read and understand for me too (and for all those who are beginners with C++),
class y_combinator_t
{
public:
function<void(y_combinator_t*, int, double, string)> callback;
void operator()(int a, double b, string s)
{
this->callback(this, a, b, s);
}
};
y_combinator_t combinator = {
[id_work = 1]
(y_combinator_t* _this, int a, double b, string s) mutable -> void
{
if(id_work == 1)
{
//...
AsyncWork1(*_this, 2, 3.0, "bla bla");
id_work = 2;
}
else if(id_work == 2)
{
//...
AsyncWork2(*_this, 3, 0.0, "bla bla");
id_work = 3;
}
else if(id_work == 3)
{
//...
}
}
};
//Start works
combinator(0, 0, "");

Construct variadic template argument list

Say i have the following scenario:
namespace detail
{
using duk_c_function_t = std::function<duk_ret_t(duk_context*)>;
template<typename T_Return(typename ... T_Params), std::function<T_Return(T_Params)>
duk_ret_t duk_function_proxy(duk_context* ctx)
{
const int n = sizeof...(T_Params); //real number of arguments passed.
duk_idx_t num_arguments = duk_get_top(ctx); //Number of arguments from javascript
int x = duk_require_int(ctx, 0); //Get integer -> parameter no 1
const char* c = duk_require_string(ctx, 1); //Get string -> parameter no 2
}
}
template<typename T_Return(typename ... T_Params)>
duk_c_function_t duk_function(std::function<T_Return(T_Params ...) function_item)
{
return duk_c_function_t(detail::duk_function_proxy<function_item>);
}
Where duk_function returns a function of the signature duk_ret_t function(duk_context* ctx) { ... }. Now, i know how to call the function object in duk_function_proxy with the variadic templates and such. But there is one problem for me: The javascript interpreter i am using requires that, for every c-function i want to expose, i need query the parameters from the stack, as shown in duk_function_proxy. However, with that being the case, i dont know how to call the function object - i can only store the queried parameters in some sort of container, and thus i cannot call the function object with the given signature. Is there any way to store my queried parameters in some sort of container, and then unpack and pass it to the function object as parameters? I query the required parameters based on the variadic template list, as seen in the prototype.
In short:
I want to iterate over T_Params, get and store the corresponding variables using duk_require_* (in some sort of container), and then use those values to call the function object, which is passed as a template argument.
this should get you started. I've simulated the DUK interface since it's not installed on my machine but you'll get the idea:
#include <iostream>
#include <string>
#include <functional>
#include <utility>
struct duk_context;
const char* duk_require_string(duk_context*, int i)
{
static constexpr const char * strings[] = {
"i like",
"hairy",
"ducks"
};
return strings[i];
}
int duk_require_int(duk_context*, int i)
{
return i * 6;
}
template<class Type> auto get_arg(duk_context* ctx, int i) -> Type;
template<> auto get_arg<std::string>(duk_context* ctx, int i) -> std::string
{
return duk_require_string(ctx, i);
}
template<> auto get_arg<int>(duk_context* ctx, int i) -> int
{
return duk_require_int(ctx, i);
}
template<class...Args, size_t...Is>
void get_args_impl(duk_context* context, const std::function<void(Args...)>& f, std::index_sequence<Is...>)
{
using tuple_type = std::tuple<Args...>;
f(get_arg<std::tuple_element_t<Is, tuple_type>>(context, Is)...);
}
template<class...Args>
void get_args(duk_context* context, const std::function<void(Args...)>& f)
{
get_args_impl<Args...>(context, f, std::index_sequence_for<Args...>());
}
void foo(std::string a, int b, std::string c)
{
std::cout << a << " " << b << " " << c << std::endl;
}
int main()
{
duk_context* ctx = nullptr;
get_args(ctx, std::function<void(std::string, int, std::string)>(&foo));
return 0;
}
expected output:
i like 6 ducks

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 <>