5

So I have a function that takes a variable length argument list, for example:

int avg(int count,...){
    //stuff
}

I can call it with avg(4,2,3,9,4); and it works fine. It needs to maintain this functionality.

Is there a way for me to also call it with an array instead of listing the variables? For example:

avg(4,myArray[5]) such that the function avg doesn't see any difference?

4
  • No, there isn't. It would be much easier to change the function itself to take an initializer list. Commented Aug 14, 2013 at 11:13
  • 2
    Function overloading? Commented Aug 14, 2013 at 11:14
  • function overloading presents me with the same problem. I still can't have an argument list with a dynamic length at runtime. I realise there are a thousand ways to do this without ... but I was wondering if I could do it without changing the function. Commented Aug 14, 2013 at 11:23
  • Define what you can change. Also this avg(4,myArray[5]) looks strange, please clarify that., it would be best to provide unit test which should pass. Commented Jun 27, 2022 at 9:00

5 Answers 5

5

No there is no such way. You can however make two functions, one that takes a variable number of arguments, and one that takes an array (or better yet, an std::vector). The first function simply packs the arguments into the array (or vector) and calls the second function.

Sign up to request clarification or add additional context in comments.

1 Comment

Ok, thanks, I thought it might be impossible but I wanted to make sure. I was hoping there might be some way to type cast into whatever type a variable length argument list is.
3
void f() {}

template<typename T, std::size_t N>
void f(T array[N])
{
}

template<typename T, typename... Args>
void f(const T& value, const Args&... args)
{
    process(value);
    f(args...);
}

Comments

2

No. Since pointers are essentially unsigned integers it would not be able to tell the difference between a memory address and an unsigned integer. Alternatively (as I am sure you wanted to avoid), you would have to do:

avg( 4, myArray[ 0 ], ..., myArray[ 3 ] );

... where ... is myArray at positions 1 and 2 if you wanted to conform with the same parameters as your previous function. There are other ways to do this, such as using C++ vectors.

Comments

0

You can easily do it

struct{int arr[100];}p;

double avg2(int count,int* arr){
    memcpy(&p,arr,count*sizeof(int));
    return avg(count,p);
}

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
Use of global variable to pass arguments is worst possible approach and this doesn't meet requirement, original avg is not in use.
0

Better approach would be get rid of variadic arguments. This was inherited from C and it is a good practice to avoid it as much as possible.

Now your example avg(4,myArray[5]) is a bit fuzzy. I assume, that first argument defines how much items must be taken from array and second argument you planned to pass just an array. I assume this index operator is typo or limping method showing array size.

So you expect something like this:

int avg(int count, ...)
{
    int sum = 0;
    std::va_list args;
    va_start(args, count);
    for (int i = 0; i < count; ++i) {
        sum += va_arg(args, int);
    }
    va_end(args);
    return sum / count;
}

template <size_t N, size_t... I>
int avg_helper(size_t count, const int (&arr)[N], std::index_sequence<I...>)
{
    return avg(count, arr[I]...);
}

template <size_t N>
int avg(int count, const int (&arr)[N])
{
    if (count > N)
        throw std::invalid_argument { "to large count passed" };
    return avg_helper(count, arr, std::make_index_sequence<N> {});
}

https://godbolt.org/z/7v1n7zaWq

Now note that in overload resolution variadic function is match as a last one. So when compiler can match template it will select it instead variadic function.

Note there is a trap. If you will pass a pointer (for example array decay) variadic argument function will kick in again. So as protection I've added extra overload which will trigger static_assert warning about array decay.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.