在不知道 C++ 中有多少个可选参数的情况下,如何在循环中使用 va_arg?

How can I use va_arg in a loop without knowing how many optional arguments there are in C++?

我想编写一个函数,它至少接受两个整数和 returns 传递给该函数的所有整数的总和:

int sumOfAtLeastTwoIntegers(int a, int b, ...){
   
    int sum = a+b;
    va_list ptr;
    va_start(ptr,b);
    for(){
        sum += va_arg(ptr, int)
    }

    va_end(ptr);
    return sum;
}

我想知道 for 循环中的表达式如何才能使循环继续,直到所有可选参数都添加到总和中。 在不知道有多少可选参数传递给函数的情况下如何实现这一点? 函数调用如下所示:

sumOfAtLeastTwoIntegers(2,3,4,5,1,0,200);

通常有两种方法来处理可变参数、先验知识和post-知识。

预知就像 printf("%d %c\n", anInt, aChar),前面有一个参数,您可以使用它来计算剩余的数量。一个例子是:

int sumOfInts(size_t count, int a, ...); // Needs "count" integers.
int eleven = sumOfInts(2, 4, 7);

Post——知识要求你有一个哨兵值,告诉你什么时候停止,比如with:

int sumOfNonZeroInts(int a, ...); // Needs non-zero integers, stops at 0.
int eleven = sumOfInts(4, 7, 0);

可能 想要考虑的另一件事是避免使用可变参数列表,C++ 中有更多表达方式来执行您想要的操作,例如向量.以下提供了一种执行此操作的方法:

#include <iostream>
#include <vector>

template<typename T> T sumOf(const std::vector<T> &vec) {
    T acc = T();
    for (const T &item: vec)
        acc += item;
    return acc;
}

int main() {
    auto eleven = sumOf<int>({4, 7}); 
    std::cout << "Four plus seven is equal to " << eleven << '\n';
}

这不一定像可变参数那样快速,但我现在的默认立场是通常首先优化可读性:-)

可以通过三种方式处理变参函数:

  1. 要么有某种终止符,一个唯一意义是终止参数列表的参数。

  2. 使第一个参数成为传递的参数数量的计数。

  3. 某种参数匹配格式,例如printfscanf.

对于您的函数类型,前两个变体都可能是很好的解决方案(取决于参数中允许的值范围)。

我建议使用如下所示的可变参数模板。只有当你至少给它两个整数时它才有效。而且所有的参数也必须是整数。

#include<iostream>
#include <type_traits>

template< typename ... Args>
std::enable_if_t<std::is_same_v<std::common_type_t<Args...>, int>, int>
sum(int arg1, Args...args)
{
    return (args+...+arg1);
}
int main(){

    std::cout << sum(1,2);//working
    std::cout << sum(1,.2);//compile error
    std::cout << sum(1);//compile error
 
}

将第一个参数用作“输入大小”,就像使用常规数组(尤其是在 C 语言中)一样。

int sumOfAtLeastTwoIntegers(int howMany, ...) {
   
    int sum = 0
    va_list ptr;
    va_start(ptr,b);
    while(howMany--){
        sum += va_arg(ptr, int)
    }

    va_end(ptr);
    return sum;
}