如何使用指针编写参数数量可变的函数?
How do I write a function with variable number of arguments using pointers?
所以我的任务是使用指针编写一个参数数量可变的函数“mult”。而且这个函数必须计算浮点数的乘积。
我已经按照大学给我们的指南进行操作,但我的乘积仍然为零。我发现问题是每隔一个要相乘的数字都是零。
#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;
}
以下是指南中的示例:
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;
您可以将 mult
编写为可变函数,并使用 std::accumulate
和 std::multiplies
作为运算符。
#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;
}
输出
3.59251e+09
我会非常担心此代码的有效性。
- 椭圆形参数是在寄存器中传递还是在堆栈中传递。 Calling conventions 对于 64 位表示前几个 pointer/int/etc 在寄存器中传递。
- 就算椭圆形参数是压栈传递的,
k
肯定不是,会放到寄存器中。所以你不能获取它的地址。
- Ellipse 参数是 default argument promoted,这意味着所有浮点数都转换为双精度数,因此当您尝试转换为 int 时,您会得到半个双精度数。
我认为这只是因为一些未定义的行为才起作用,而且我什至怀疑因为 pt。 3.
好吧,如果您必须使用指针,这里有一个解决方案:
#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;
}
使用 C++17
的 fold expressions 函数,就像您描述的那样,创建起来非常简单:
template<typename... Args>
auto mult(Args... args)
{
// Parenthesis are required
return (... * args);
}
上面的折叠表达式展开为:
((arg_1 * arg_2) * arg_3) * ...) * arg_n)
任何二元运算符都可以用来代替乘法:
// Sum
return (... + args);
// and
return (... && args);
您还可以使用这些执行相当复杂的操作:
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
虽然 comma_sep_print
中的折叠逗号看起来很奇怪,但扩展非常简单:
(std::cout << ", " << 2, std::cout << ", " << 3) << '\n`;
所以我的任务是使用指针编写一个参数数量可变的函数“mult”。而且这个函数必须计算浮点数的乘积。
我已经按照大学给我们的指南进行操作,但我的乘积仍然为零。我发现问题是每隔一个要相乘的数字都是零。
#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;
}
以下是指南中的示例:
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;
您可以将 mult
编写为可变函数,并使用 std::accumulate
和 std::multiplies
作为运算符。
#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;
}
输出
3.59251e+09
我会非常担心此代码的有效性。
- 椭圆形参数是在寄存器中传递还是在堆栈中传递。 Calling conventions 对于 64 位表示前几个 pointer/int/etc 在寄存器中传递。
- 就算椭圆形参数是压栈传递的,
k
肯定不是,会放到寄存器中。所以你不能获取它的地址。 - Ellipse 参数是 default argument promoted,这意味着所有浮点数都转换为双精度数,因此当您尝试转换为 int 时,您会得到半个双精度数。
我认为这只是因为一些未定义的行为才起作用,而且我什至怀疑因为 pt。 3.
好吧,如果您必须使用指针,这里有一个解决方案:
#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;
}
使用 C++17
的 fold expressions 函数,就像您描述的那样,创建起来非常简单:
template<typename... Args>
auto mult(Args... args)
{
// Parenthesis are required
return (... * args);
}
上面的折叠表达式展开为:
((arg_1 * arg_2) * arg_3) * ...) * arg_n)
任何二元运算符都可以用来代替乘法:
// Sum
return (... + args);
// and
return (... && args);
您还可以使用这些执行相当复杂的操作:
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
虽然 comma_sep_print
中的折叠逗号看起来很奇怪,但扩展非常简单:
(std::cout << ", " << 2, std::cout << ", " << 3) << '\n`;