Reputation: 13
So I have a task to write a function "mult" with variable number of arguments using pointers. And this function must calculate the product of float numbers.
I've followed the guide that our uni gave us but my product is still equal to zero. I found out that the problem is that every other number to be multiplied is zero.
#include <iostream>
using namespace std;
int mult(int k,...){
int* p = &k;
int m = 1;
for(; k != 0; k--){
m *= *(++p);
}
return m;
}
int main(){
float res1 = mult(11,45,10,9,8,7,6,5,4,3,2,2);
float res2 = mult(7,12,23,0.3,0.6,1,2);
float res3 = mult(3,0.6,-12,-0.9);
cout << "Your results are:\n"
<<res1<<"\n"
<<res2<<"\n"
<<res3<<"\n";
return 0;
}
Here's examples from guide:
void Print_stor(int k, ...)
{
int n=k;
int a[n];
int *p = &k;
for ( ; k!=0;k--)
a[k-1]=*(++p);
for(int i=n-1; i>=0; i--)
printf("%i ", a[i]);
printf("\n");
}
int sum(int k, …)
{
int *p = &k;
int s=0;
for ( ; k!=0; k--)
s+=*(++p);
return s;
Upvotes: 1
Views: 173
Reputation: 371
With C++17
's fold expressions functions like the one you described are really simple to create:
template<typename... Args>
auto mult(Args... args)
{
// Parenthesis are required
return (... * args);
}
The fold expression above expands as:
((arg_1 * arg_2) * arg_3) * ...) * arg_n)
Any binary operator can be used to replace the multiplication:
// Sum
return (... + args);
// and
return (... && args);
You can also perform rather complicated stuff with these:
template<typename T, typename... Args>
void comma_sep_print(const T& first, const Args&... args)
{
std::cout << first;
// Fold over comma operator
((std::cout << ", " << args), ...) << '\n';
}
comma_sep_print(1, 2, 3);
// Outputs: 1, 2, 3
Albeit the fold over comma in comma_sep_print
looks strange, the expansion is quite straightforward:
(std::cout << ", " << 2, std::cout << ", " << 3) << '\n`;
Upvotes: 0
Reputation: 668
Well, if you must use a pointer, here is a solution with one:
#include <functional>
#include <initializer_list>
#include <iostream>
#include <numeric>
#include <memory>
template<typename T, typename... Args>
T mult(T t, Args... args)
{
std::unique_ptr<std::initializer_list<T>> p = std::make_unique<std::initializer_list<T>>(std::initializer_list<T>{args...});
return std::accumulate(p->begin(), p->end(), t, [](auto a, auto b){return a*b;});
}
int main()
{
std::cout << mult<float>(1.0,2.0,3.0,4.0);
return 0;
}
Upvotes: 0
Reputation: 16099
I would have so many worries over this code's validity.
k
is certainly not, it would be placed in a register. And so you can't take its address.I would think this only works because of some undefined behaviour if at all, and I doubt even that because of pt. 3.
Upvotes: 0
Reputation: 117866
You could write mult
as a variadic function, and use std::accumulate
with std::multiplies
as the operator.
#include <functional>
#include <initializer_list>
#include <iostream>
#include <numeric>
template<typename T, typename... Args>
T mult(T t, Args... args)
{
std::initializer_list<T> values{args...};
return std::accumulate(values.begin(), values.end(), t, std::multiplies<T>());
}
int main()
{
std::cout << mult<float>(11,45,10,9,8,7,6,5,4,3,2,2);
return 0;
}
Output
3.59251e+09
Upvotes: 5