This should (and does) assign a random character from the given arguments to a.
In this case, a would ultimately equal 'a', 'b', or 'c'.

The final argument should always be NULL. The function will continue to check arguments for possible return values until the argument NULL is found.

The problem arises when I want to use a value equivalent to zero as an argument, such as the integer 0 or the character '\0'.
The function simply ignores the zero (or '\0'), as well as any arguments following it.

For example:

int b = choose(5, 9, 3, 0, 17, 16, 92, NULL);

This will assign either 5, 9, or 3 to the variable b. Everything after 0, including 0 itself, is completely ignored. This is obviously not how the function is supposed to behave.

It would seem that 0, NULL, and '\0' all have equivalent values, so if any of them are entered before the true final argument, then they are recognized as the final argument, and all arguments after them are ignored accordingly.

I've tried replacing NULL with (char)1, but that yielded the same issue, only with ones being excluded instead of zeroes.
Is there something other than NULL that I could use for my final argument that wouldn't yield such an issue? (such as a constant value that can only be obtained by explicitly entering its name)

I would prefer a solution that would still support the use of a template, but if that's impossible, then I'll take what I can get.

Thanks in advance; your help will be appreciated.

Here is the code for the function itself:

123456789101112131415161718192021222324252627282930313233343536

template <typename T>
T choose (T arg1, ...)
{
int argsCount = 0; //the number of arguments
va_list list; //declares the variable argument list
va_start(list,arg1); //starts the variable argument list
T currentArg; //the current argument within the loopdo//a do while() loop is used instead of a while() loop just in case the garbage in currentArg is a NULL character
{
currentArg = va_arg(list,T); //assign the value of the current argument in the list to currentArgif (currentArg != NULL)
{
argsCount++; //increment the number of arguments
}
} while(currentArg != NULL); //while the current argument is not NULL. This loop gets the number of arguments.
va_end(list); //resets the variable argument list to NULL so that it can be called again properlyint choice = random.roll_range(-1, argsCount - 1); //sets the location of the choice in the list to a random int >=-1 and <=argsCount. If -1, then return the first argument.if ( choice == -1 )
{
return arg1; //returns arg1, the first argument in the function call
}
else//if choice is not -1, then an argument from the variable argument list must be chosen.
{
va_start(list,arg1); //starts the variable argument list againfor( int i = 0; i < argsCount; i++ )
{
T currentArg = va_arg(list,T); //assign the value of the current argument in the list to currentArgif (i == choice)
{
return currentArg; //returns the chosen argument
}
}
va_end(list); //resets the variable argument list to NULLreturn NULL; //returns NULL if the function failed to choose an argument
}
}

Note: random.roll_range returns a random integer between two integer parameters, min and max. I know for a fact that this is not where the issue is occurring, but just in case it is necessary, here is the code for random.roll_range:

Just make the first argument be an unsigned int equal to the number of arguments to choose between? Otherwise this will always be an issue, especially if you want it to work across a variety of data types. I'd suggest using a longer watch value like 0xDEADBEEF (thanks for that one, MS), but when you're dealing with potentially single byte data types that wouldn't work out so well.

Thank you for your response, but that's actually what I'm trying to avoid.

The reason that I am implementing NULL as the final parameter in the first place is because I want to be able to enter any number of arguments without having to explicitly state the number of arguments each time.

The point is for it to count each argument until it hits NULL, which should be the final argument. It's sort of a matter of convenience, considering I may end up using this function to choose upwards of 100 arguments in the future.

By implementing NULL as the final parameter, I've removed the need for stating the number of arguments as the first parameter, and it works perfectly, so long as a value equivalent to zero does not need to be a parameter.

That's actually a very good point, and it's given me an idea. Since the datatype of arg1 determines the datatype of all of the following arguments, perhaps I can create conditionals within the function to check the datatype being passed, and replace NULL with the maximum possible value of said datatype. I'm going to try that out. I'll let keep you updated on how it goes.

(Obviously this would result in me not being able to use the character 255, but I honestly don't see any circumstances where I would need to randomly choose it)

Disclaimer: I don't really know what I am talking about - Just putting forward an idea that I suspect might be right. I hope it helps, or at least provides a clue. I am sure know there are others on this forum who know vastly more than me.

Well TheIdeasMan, I've been researching both of those examples to the best of my ability.
The second one seems to give me all sorts of syntax errors (visual c++ 2010 doesn't seem to like the "const Args&... args" being used as a parameter.
The first one works to a degree, but I get an error when I directly try to type something along the lines of:funcName({1, 2, 3});

In any case, I would assume that I'm biting off more than I can chew with variable arguments, so I'm going to have to just settle for having it choose from an array for now, and come back to this when I have a more firm grasp on the concept.

If you're interested, here's the new, extremely simplified code:

1234567

#define ARR_LENGTH(a) (sizeof(a) / sizeof(a[0])) //macro for number of elements in an arraytemplate <typename T>
T choose (T args[], int length) //returns a random element from an array. The second argument should be ARR_LENGTH(args)
{
return args[random.roll(length-1)]; //returns a random element from args[]
}

Comparing it to the original code, it's a bit anticlimactic, but it serves its purpose. The only downside is that I now need to add all of the arguments to an array before they can be passed, but that's not too much of a hassle.

In any case, thank you both for your help as well as your time. You've given me some good ideas, and directed me to some areas that I obviously need to do some more research on.

Now, I'm fairly new to this forum (in that this was my first post), so one final question. Is this sufficient enough to mark this topic as solved, or should I leave it open?