如何使用指针编写参数数量可变的函数?

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

我会非常担心此代码的有效性。

  1. 椭圆形参数是在寄存器中传递还是在堆栈中传递。 Calling conventions 对于 64 位表示前几个 pointer/int/etc 在寄存器中传递。
  2. 就算椭圆形参数是压栈传递的,k肯定不是,会放到寄存器中。所以你不能获取它的地址。
  3. 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++17fold 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`;