Reputation: 6039
#include <iostream>
using namespace std;
class SampleClass
{
public:
int test(int ... arguments)
{
cout << arguments[0] << endl; // Access first element in array
return sizeof(arguments);
}
};
int main()
{
SampleClass lol;
cout << lol.test(3, 1, 4, 2, 5, 0) << endl;
return 0;
}
The test
function fails due to my limited understanding in C++ semantics. But how can I fix it so that it can access the FIRST element in the arguments lits and then return the size of arguments
?
Upvotes: 1
Views: 147
Reputation: 42554
Since we're all guessing at what you want, I'll throw in:
template <typename ... Ts>
size_t test(Ts ... arguments) {
auto unused = { 0, ((cout << '[' << arguments << "]\n"), 0)...};
(void)unused;
return sizeof...(arguments);
}
which works with different types of arguments (Live at Coliru). This solution is a bit too "clever" to be readable, though.
The trick here is to build a braced-initializer-list - the {...}
stuff - whose elements are initialized by processing the variadic arguments in order. You then convince the compiler that said initializer list isn't used for anything, so the code will be optimized to just generate the desired side effects.
The comma operator in C++ evaluates to the value of the rightmost subexpression. The other subexpressions are evaluated and their values discarded. So ((cout << '[' << arguments << "]\n"), 0)
has the effect of dumping some stuff to cout
- including one of the variadic parameters - and evaluates to 0. After expanding the pack with the ...
that line of code is effectively:
auto unused = { 0, ((cout << '[' << arg0 << "]\n"), 0),
((cout << '[' << arg1 << "]\n"), 0),
((cout << '[' << arg2 << "]\n"), 0) };
The cout
junk is evaluated for its side effects and discarded, the whole thing is deduced as a std::initializer_list<int>
just as if we had written
auto unused = { 0, 0, 0, 0 };
(The extra zero is there at the beginning to avoid a syntax error if someone calls the function with no arguments at all.)
The (void)unused;
line is casting unused
to void
. It will compile to absolutely nothing, but also will typically tell compilers not to warn us about unused
being an unused variable.
Upvotes: 3
Reputation: 66194
I am not quite sure I fully understand your question. If you want access to "the first" argument to the function rather than the template, I think something like this will do it for you, but I may be completely misunderstanding your purpose here:
#include <iostream>
template<typename... Args>
int foo(int arg0, Args... args);
template<>
int foo(int arg0)
{
// here just to catch expansion
std::cout << '[' << arg0 << ']' << std::endl;
return 1;
}
template<typename... Args>
int foo(int arg0, Args... args)
{
foo(arg0);
foo(args...);
return 1 + sizeof...(args);
}
int main()
{
std::cout << foo(1,2,3,4,5) << std::endl;
std::cout << foo(100,200,300) << std::endl;
int a=10, b=20;
std::cout << foo(a,b) << std::endl;
return 0;
}
Output
[1]
[2]
[3]
[4]
[5]
5
[100]
[200]
[300]
3
[10]
[20]
2
Upvotes: 2
Reputation: 7960
You have several options.
1) use an ellipse (only way to have unlimited arg list):
int foo(int a1, ...);
Your code will need to parse the ellipse like printf does. you'll be limited to builtin C types.
2) Use multiple templates:
template<typename T1> int foo(T1 a1);
template<typename T1, typename T2> int foo(T1 a1, T2 a2);
// more templates for more arguments
This method us used, usually up to 10 parameters (10 template functions)
3) Use a function with defaults or illegal values so you'll know which is the last valid argument:
int foo(int a1, int a2 = -1, int a3 = -1, int aN = -1);
Upvotes: 1
Reputation: 55887
Hm. You are trying to mix two features of C++, variadic-templates
and variable-length argument list
.
Your code will not compile at all, since you have no templates here and for variable-length argument list
declaration should be
int test(int arguments...)
and you can access values from this list with functions from cstdarg
header.
With variadic-templates
you can do following thing
class Derived
{
public:
template<int... arguments>
int test()
{
int array[] = {arguments...};
return sizeof(array) / sizeof(*array);
}
};
use it like
cout << lol.test<3, 1, 4, 2, 5, 0>() << endl;
Upvotes: 3
Reputation: 465
try something like this
double test( int num, ... )
{
va_list arguments; // A place to store the list of arguments
double sum = 0;
va_start ( arguments, num ); // Initializing arguments to store all values after num
for ( int x = 0; x < num; x++ ) // Loop until all numbers are added
sum += va_arg ( arguments, double ); // Adds the next value in argument list to sum.
va_end ( arguments ); // Cleans up the list
return sum / num; // Returns the average
}
so youre points are on the wrong side of your parameter list. i hope this helps and goodluck.
Upvotes: 3