How I can have variable number of parameters in my function in C++.
Analog in C#:
public void Foo(params int[] a) {
for (int i = 0; i < a.Length; i++)
Console.WriteLine(a[i]);
}
public void UseFoo() {
Foo();
Foo(1);
Foo(1, 2);
}
Analog in Java:
public void Foo(int... a) {
for (int i = 0; i < a.length; i++)
System.out.println(a[i]);
}
public void UseFoo() {
Foo();
Foo(1);
Foo(2);
}
These are called Variadic functions. Wikipedia lists example code for C++.
To portably implement variadic
functions in the C programming
language, the standard stdarg.h header
file should be used. The older
varargs.h header has been deprecated
in favor of stdarg.h. In C++, the
header file cstdarg should be used.
To create a variadic function, an
ellipsis (...) must be placed at the
end of a parameter list. Inside the
body of the function, a variable of
type va_list must be defined. Then the
macros va_start(va_list, last fixed
param), va_arg(va_list, cast type),
va_end(va_list) can be used. For
example:
#include <stdarg.h>
double average(int count, ...)
{
va_list ap;
int j;
double tot = 0;
va_start(ap, count); //Requires the last fixed parameter (to get the address)
for(j=0; j<count; j++)
tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return tot/count;
}
The real C++ solution is variadic templates. You'll need a fairly recent compiler and enable C++11 support if needed.
Two ways to handle the "do the same thing with all function arguments" problem: recursively, and with an ugly (but very very Standards compliant) solution.
The recursive solution looks somewhat like this:
template<typename... ArgTypes>
void print(ArgTypes... args);
template<typename T, typename... ArgTypes>
void print(T t, ArgTypes... args)
{
std::cout << t;
print(args...);
}
template<> void print() {} // end recursion
It generates one symbol for each collection of arguments, and then one for each step into the recursion. This is suboptimal to say the least, so the awesome C++ people here at SO thought of a great trick abusing the side effect of a list initialization:
struct expand_type {
template<typename... T>
expand_type(T&&...) {}
};
template<typename... ArgTypes>
void print(ArgTypes... args)
{
expand_type{ 0, (std::cout << args, 0)... };
}
Code isn't generated for a million slightly different template instantiations, and as a bonus, you get preserved order of you function arguments. See the other answer for the nitty gritty details of this solution.
In C++11 and later you can also use initializer lists.
int sum(const initializer_list<int> &il)
{
int nSum = 0;
for (auto x: il)
nSum += x;
return nsum;
}
cout << sum( { 3, 4, 6, 9 } );
Aside from the other answers, if you're just trying to pass an array of integers, why not:
void func(const std::vector<int>& p)
{
// ...
}
std::vector<int> params;
params.push_back(1);
params.push_back(2);
params.push_back(3);
func(params);
You can't call it in parameter, form, though. You'd have to use any of the variadic function listed in your answers. C++0x will allow variadic templates, which will make it type-safe, but for now it's basically memory and casting.
You could emulate some sort of variadic parameter->vector thing:
// would also want to allow specifying the allocator, for completeness
template <typename T>
std::vector<T> gen_vec(void)
{
std::vector<T> result(0);
return result;
}
template <typename T>
std::vector<T> gen_vec(T a1)
{
std::vector<T> result(1);
result.push_back(a1);
return result;
}
template <typename T>
std::vector<T> gen_vec(T a1, T a2)
{
std::vector<T> result(1);
result.push_back(a1);
result.push_back(a2);
return result;
}
template <typename T>
std::vector<T> gen_vec(T a1, T a2, T a3)
{
std::vector<T> result(1);
result.push_back(a1);
result.push_back(a2);
result.push_back(a3);
return result;
}
// and so on, boost stops at nine by default for their variadic templates
Usage:
func(gen_vec(1,2,3));
See Variadic functions in C, Objective-C, C++, and D
You need to include stdarg.h and then use va_list, va_start, va_arg and va_end, as the example in the Wikipedia article shows. It's a bit more cumbersome than in Java or C#, because C and C++ have only limited built-in support for varargs.
If you don't care about portability, you could port this C99 code to C++ using gcc's statement expressions:
#include <cstdio>
int _sum(size_t count, int values[])
{
int s = 0;
while(count--) s += values[count];
return s;
}
#define sum(...) ({ \
int _sum_args[] = { __VA_ARGS__ }; \
_sum(sizeof _sum_args / sizeof *_sum_args, _sum_args); \
})
int main(void)
{
std::printf("%i", sum(1, 2, 3));
}
You could do something similar with C++0x' lambda expressions, but the gcc version I'm using (4.4.0) doesn't support them.
GManNickG and Christoph answers are good, but variadic functions allow you push in the ... parameter whatever you want, not only integers. If you will want in the future, to push many variables and values of different types into a function without using variadic function, because it is too difficult or too complicated for you, or you don't like the way to use it or you don't want to include the required headers to use it, then you always can use void** parameter.
For example, Stephan202 posted:
double average(int count, ...)
{
va_list ap;
int j;
double tot = 0;
va_start(ap, count); //Requires the last fixed parameter (to get the address)
for(j=0; j<count; j++)
tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return tot/count;
}
this can be also written as:
double average(int count, void** params)
{
int j;
double tot = 0;
for (j=0; j<count; j++)
tot+=*(double*)params[j];
return tot/count;
}
Now use it like this way:
int _tmain(int argc, _TCHAR* argv[])
{
void** params = new void*[3];
double p1 = 1, p2 = 2, p3 = 3;
params[0] = &p1;
params[1] = &p2;
params[2] = &p3;
printf("Average is: %g\n", average(3, params));
system("pause");
return 0;
}
for full code:
#include "stdafx"
#include <process.h>
double average(int count, void** params)
{
int j;
double tot = 0;
for (j=0; j<count; j++)
tot+=*(double*)params[j];
return tot/count;
}
int _tmain(int argc, _TCHAR* argv[])
{
void** params = new void*[3];
double p1 = 1, p2 = 2, p3 = 3;
params[0] = &p1;
params[1] = &p2;
params[2] = &p3;
printf("Average is: %g\n", average(3, params));
system("pause");
return 0;
}
OUTPUT:
Average is: 2
Press any key to continue . . .
I do mine like this in c++ builder xe.xx:
String s[] = {"hello ", " unli", " param", " test"};
String ret = BuildList(s, 4);
String BuildList(String s[], int count)
{
for(int i = 0; i < count; i++)
{
//.... loop here up to last s[i] item ...
}
}
Related
In my project i have functions with different number of input parameters with different types. Since these functions are parts of libraries, I cannot change their definitions or bodies.
void methodA(boolean p1, int p2, long p3){
... some unrelevant code here ...
}
void methodB(int p1, int p2, int p3, long p4){
... some unrelevant code here too ...
}
int methodC(long p4){
...
}
In my project i need to have a method, which would receive the address of one of these functions. Additionally it receives well-formed list of parameters (which fits the function in the first parameter). Then this method has to call the passed function with the passed parameters.
Here is what I have now: (i have simplified the code a bit to make my idea clear)
void intercaller(void* some_func_address, ...){
// VARARGS parameters extractor
va_list listPointer;
va_start( listPointer, some_func_address );
int p1 = va_arg( listPointer, int );
int p2 = va_arg( listPointer, int );
int p3 = va_arg( listPointer, int );
long p4 = va_arg( listPointer, long );
// TODO: THIS IS NOT GENERIC CALL , CANN ONLY CALL METHOD B
((void (*)( int , int , int , long )) some_func_address)( p1 , p2 , p3 , p4 );
va_end( listPointer );
}
My problem is the actual function call. The parameter list in the function call should be generic and should be able to include different number of parameters, sadly i dont know how to do that... I have tried passing varargs list like here:
((void (*)( va_list )) some_func_address)( listPointer);
but this messes up the parameters in the called function...
So my question is: is there a way to call a given function with given parameters in a generic manner? Maybe I need some sort of a typedeff or a wrapper function?
If you don't have std::invoke yet, use variadic templates. To treat void functions nicely, use SFINAE.
template<typename R, typename... Args>
auto call(R(*function)(Args...), Args... args) -> typename std::enable_if<!std::is_same<R, void>::value, R>::type {
return function(args...);
}
template<typename... Args>
void call(void (*function)(Args...), Args... args) {
function(args...);
}
Example:
void a() {
std::cout << 'a';
}
void b(int a) {
std::cout << "b:" << a;
}
int c(int a) {
return a;
}
int main() {
call(a);
call(b, 1);
std::cout << "c:" << call(c, 2);
}
Don't forget to #include <type_traits> for std::enable_if and std::is_same.
Try it online!
va_args are still somewhat black magic to me, but I believe the second arg to va_start should be the first arg to the called function. I don't understand what your "clazz" is. I believe you you should call va_start as:
va_start( listpointer, some_func_address );
instead of:
va_start( listPointer, clazz );
Would this help you out?
#include <stdarg.h>
template <typename T>
T extract(va_list& list)
{
return va_arg(list, T);
}
template<typename Result, typename ... Parameters>
Result call(Result(*function)(Parameters...), va_list& list)
{
return function(extract<Parameters>(list)...);
}
void f1(int x, int y)
{
std::cout << x << ' ' << y << std::endl;
}
void f2(double x, double y)
{
std::cout << x << ' ' << y << std::endl;
}
void interceptor(void* f, ...)
{
va_list list;
va_start(list, f);
if(f == &f1)
{
call(f1, list);
}
else if(f == f2)
{
call(f2, list);
}
va_end(list);
}
int main(int argc, char* argv[])
{
interceptor((void*)&f1, 7, 7);
interceptor((void*)&f2, 10.12, 12.10);
return 0;
}
I personally would yet prefer pasing an enum representing the functions to the interceptor function instead of the void* pointer and using switch/case inside.
If you can make the interceptor a template function, it gets even much easier (drop the call template function entirely):
template<typename Result, typename ... Parameters>
void interceptor(Result(*function)(Parameters...), ...)
{
va_list list;
va_start(list, function);
function(extract<Parameters>(list)...);
va_end(list);
}
int main(int argc, char* argv[])
{
interceptor(&f1, 7, 7);
interceptor(&f2, 10.12, 12.10);
return 0;
}
Now coming from your other question, what about this:
(Side note: referenced question tells (in the comments) the void* pointers are coming from some custom map, so there shouldn't be – as far as I can see – any issue with replacing them by other appropriate pointers/classes – which I am going to do...)
#include <stdarg.h>
class FunctionWrapper
{
public:
virtual ~FunctionWrapper() { }
virtual void operator()(va_list&) = 0;
};
template<typename Result, typename ... Parameters>
class FWrapper : public FunctionWrapper
{
Result (*mFunction)(Parameters...);
template <typename T>
T extract(va_list& list)
{
return va_arg(list, T);
}
public:
FWrapper(Result (*function)(Parameters...))
: mFunction(function)
{ }
virtual void operator()(va_list& list)
{
static_cast<void>(mFunction(extract<Parameters>(list)...));
}
};
// facilitates creating the wrappers:
template<typename Result, typename ... Parameters>
FunctionWrapper* createWrapper(Result (*function)(Parameters...))
{
return new FWrapper<Result, Parameters ...>(function);
}
void f1(int x, int y)
{
std::cout << x << ' ' << y << std::endl;
}
void f2(double x, double y)
{
std::cout << x << ' ' << y << std::endl;
}
// e. g.:
FunctionWrapper* gWrappers[] = { createWrapper(&f1), createWrapper(&f2) };
// from your other question: you'd fill the wrappers into the map you mentioned there:
// map[whatever] = createWrapper(&function);
void interceptor(FunctionWrapper* wrapper, ...)
{
va_list list;
va_start(list, wrapper);
(*wrapper)(list);
va_end(list);
}
int main(int argc, char* argv[])
{
interceptor(gWrappers[0], 7, 7);
interceptor(gWrappers[1], 10.12, 12.10);
return 0;
}
This solves the issue via polymorphism: A function wrapper class template class (we need a non-template base class to be able to place all the template instances into an array or a map; this is what your original – but actually illegal – void* pointer served for), resolving the va_list into arguments and calling the original function with...
I have the following code which could not be complied.
using namespace std;
void f(int);
template<typename T1, size_t N>
void array_ini_1d(T1 (&x)[N])
{
for (int i = 0; i < N; i++)
{
x[i] = 0;
}
}
What is the proper way to pass the array if the main is something like below.
int main()
{
int a;
cin >> a;
int n = a / 4;
f(n);
return 0;
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
error: no matching function to call to array_ini_1d..............
The problem is that variable size arrays are not supported by c++, and is only supported as compilers extension. That means, the standard doesn't say what should happen, and you should see if you can find in compiler's documentation, but I doubt that such corner cases are documented.
So, this is the problem :
int arr[n];
The solution is to avoid it, and use something supported by c++, like for example std::vector.
I don't think the compiler can deduce the size of a variable-length array in a template. Also, don't forget to forward declare f before you use it. Variable-length arrays are a GCC extension and you should get a warning regarding their use.
You may declare your function like this:
template <typename A, size_t N> void f(A a[N]) {
for(size_t i = 0; i < N; i++)
cout << a[i];
}
However, the problem is that when you call the function, the compiler won't deduce the template parameters, and you will have to specify them explicitly.
char arr[5] = {'H', 'e', 'l', 'l', 'o'};
int main()
{
//f(arr); //Won't work
f<char, sizeof(arr)/sizeof(arr[0])>(arr);
cout << endl;
return 0;
}
Unfortunately, that ruins the very idea...
UPD: And even that code does NOT work for an array that has variable length, for the length is calculated at runtime, and the template parameters are defined at compilation time.
UPD2: If using std::vector you may create it initialized:
vector<int> arr(n, 0);
Or you may fill it with fill from <algorithm> when needed:
std::fill(arr.begin(), arr.end(), 0);
As you use Variable length array (VLA) (compiler extension), compiler cannot deduce N.
You have to pass it by pointer and give the size:
template<typename T>
void array_ini_1d(T* a, std::size_t n)
{
for (std::size_t i = 0; i != n; ++i) {
a[i] = 0;
}
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
Or use std::vector. (no extension used so). Which seems cleaner:
template<typename T>
void array_ini_1d(std::vector<T>& v)
{
for (std::size_t i = 0, size = v.size(); i != n; ++i) {
a[i] = 0; // or other stuff.
}
}
void f(int n)
{
std::vector<int> arr(n); // or arr(n, 0).
array_ini_1d(arr);
}
Template parameters must be resolved at compile-time.
There is no way that a function template with parameter size_t N can match any sort of array or other container whose size comes from a run-time input.
You will need to provide another version of the array_1d_ini which does not have the size as a template parameter.
template<typename T, size_t N>
void f(T* a)
{
/* add your code here */
}
int main()
{
int a[10];
f<int, 10>(a);
return 0;
}
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 have the following code which could not be complied.
using namespace std;
void f(int);
template<typename T1, size_t N>
void array_ini_1d(T1 (&x)[N])
{
for (int i = 0; i < N; i++)
{
x[i] = 0;
}
}
What is the proper way to pass the array if the main is something like below.
int main()
{
int a;
cin >> a;
int n = a / 4;
f(n);
return 0;
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
error: no matching function to call to array_ini_1d..............
The problem is that variable size arrays are not supported by c++, and is only supported as compilers extension. That means, the standard doesn't say what should happen, and you should see if you can find in compiler's documentation, but I doubt that such corner cases are documented.
So, this is the problem :
int arr[n];
The solution is to avoid it, and use something supported by c++, like for example std::vector.
I don't think the compiler can deduce the size of a variable-length array in a template. Also, don't forget to forward declare f before you use it. Variable-length arrays are a GCC extension and you should get a warning regarding their use.
You may declare your function like this:
template <typename A, size_t N> void f(A a[N]) {
for(size_t i = 0; i < N; i++)
cout << a[i];
}
However, the problem is that when you call the function, the compiler won't deduce the template parameters, and you will have to specify them explicitly.
char arr[5] = {'H', 'e', 'l', 'l', 'o'};
int main()
{
//f(arr); //Won't work
f<char, sizeof(arr)/sizeof(arr[0])>(arr);
cout << endl;
return 0;
}
Unfortunately, that ruins the very idea...
UPD: And even that code does NOT work for an array that has variable length, for the length is calculated at runtime, and the template parameters are defined at compilation time.
UPD2: If using std::vector you may create it initialized:
vector<int> arr(n, 0);
Or you may fill it with fill from <algorithm> when needed:
std::fill(arr.begin(), arr.end(), 0);
As you use Variable length array (VLA) (compiler extension), compiler cannot deduce N.
You have to pass it by pointer and give the size:
template<typename T>
void array_ini_1d(T* a, std::size_t n)
{
for (std::size_t i = 0; i != n; ++i) {
a[i] = 0;
}
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
Or use std::vector. (no extension used so). Which seems cleaner:
template<typename T>
void array_ini_1d(std::vector<T>& v)
{
for (std::size_t i = 0, size = v.size(); i != n; ++i) {
a[i] = 0; // or other stuff.
}
}
void f(int n)
{
std::vector<int> arr(n); // or arr(n, 0).
array_ini_1d(arr);
}
Template parameters must be resolved at compile-time.
There is no way that a function template with parameter size_t N can match any sort of array or other container whose size comes from a run-time input.
You will need to provide another version of the array_1d_ini which does not have the size as a template parameter.
template<typename T, size_t N>
void f(T* a)
{
/* add your code here */
}
int main()
{
int a[10];
f<int, 10>(a);
return 0;
}
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 <>