简体   繁体   中英

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

I want to write a function which takes at least two integer and returns the sum of all integer passed to the function:

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;
}

I want to know how the expression in the for loop has to look like such that the loop continues until all optional arguments were added to the sum. How would I achieve this without knowing how many optional arguments were passed to the function? The function call would look like this:

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

There are generally two ways to handle variable arguments, pre-knowledge and post-knowledge.

Pre-knowledge is like with printf("%d %c\n", anInt, aChar) , there's an argument up front which you can use to figure out how many remain. An example of that would be:

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

Post-knowledge requires you to have a sentinel value that tells you when to stop, such as with:

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

One other thing you may want to consider is steering clear of variable argument lists, there are much more expressive ways in C++ for doing what you want with, for example, vectors. The following provides one way of doing this:

#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';
}

This isn't necessarily as fast as variable arguments, but my default position nowadays is to generally optimise for readability first:-)

I suggest to use a variadic template like the following. It works only if u give it two integers at least. And all of the args must be integers too.

#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
 
}

There are three ways to handle variable-argument functions:

  1. Either have some kind of terminator , an argument whose sole meaning is to terminate the argument list.

  2. Make the first argument be a count of the number of arguments passed.

  3. Some kind of argument-matching format, like eg printf or scanf .

For your kind of function, the first two variants could both be good solutions (depending on the range of values allowed in the arguments).

Use the first argument as an "input size" just how you'd do with regular arrays especially in 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM