Is there any way at all for this code to compile and work as intended without resorting to va_list stuff ?
#include <iostream>
void fct(void)
{
std::cout << std::endl;
}
void fct(int index, int indexes...)
{
std::cout << index << ' ';
fct(indexes); //or fct(indexes...); ?
}
int main(void)
{
fct(1, 2, 3, 4, 5, 6, 7);
return 0;
}
I suspect you have misunderstood the meaning of the signature
void fct (int index, int indexes...)
I suspect you think that fct() expect a int single value (index) and a variadic list of int's (indexex...) with C++11 style of parameter pack expansion.
No: it's the same as
void fct (int index, int indexes, ...)
so two int single values and a C-style of optional argument that you can use only through va_list stuff.
If you don't believe it, try calling fct() with only an integer argument
fct(1);
You should obtain an error of type "error: no matching function for call to 'fct'" with a note of type "note: candidate function not viable: requires at least 2 arguments, but 1 was provided" regarding the variadic version of fct().
If you want receive a variadic list of parameters and recursively pass the to the same function, you can use the template variadic way.
By example
template <typename ... Ts>
void fct(int index, Ts ... indexes)
{
std::cout << index << ' ';
fct(indexes...);
}
If you really dislike the idea of a template, I guess you could cheat a bit like this:
#include <iostream>
#include <vector>
void fct(std::vector<int>&& _indices)
{
for (auto&& i : _indices)
{
std::cout << i << ' ';
}
std::cout << std::endl;
}
int main(void)
{
fct({1, 2, 3, 4, 5, 6, 7}); // Note the curly braces
return 0;
}
Related
I know we can iterate through an array passed as an argument in this way:
// NO ERROR
void fun(int *a, int n){
for(int i=0; i<n; i++)
cout<<a[i];
}
But, is there any way I could iterate through an array using a for-each loop inside a function like this?
// ERROR
void fun(int *a, int n){
for(auto x:a)
cout<<x;
}
A pointer is not an array. If you pass a pointer to the first element of an array to a function then its no longer an array, but a pointer.
You can use a range based loop when you pass the array by reference:
#include <iostream>
template <size_t N>
void foo(int (&x)[N]) {
for (int i : x) std::cout << i << " ";
}
int main() {
int x[] = {1,2,3};
foo(x);
}
Output:
1 2 3
This works, because the range based loop uses std::begin(x) and std::end(x) to get iterators to the begin and end of the array. Pointers don't have a begin or end.
In C++20, you can use std::span:
#include <cstddef>
#include <cstdio>
#include <span>
void foo(int* arr, std::size_t sz) {
std::span<int> span{arr, sz};
for (int elm : span) {
std::printf("%d\n", elm);
}
}
Or you could make span the input argument in the first place:
void foo(std::span<int> span) {
for (int elm : span) {
std::printf("%d\n", elm);
}
}
If the signature of the function is flexible, I suggest you use the second option.
Pre C++20, here is an implementation of span from GSL. Or make your own wrapper class with begin() and end() functions.
Alternative non-template C++20 solution:
auto range = std::views::counted(arr, sz);
for (auto elm : range) {
The benefit of this compared to std::span is that this is more general and works with any iterator, not requiring a contiguous iterator such as a pointer.
The benefit of using std::span instead of this is that you can use std::span as the function parameter without making it a template.
Alternative template solution (works pre C++20):
template <class Range>
void foo(const Range& range) {
for (auto elm : range) {
The benefit of this compared to int (&arr)[N] is that it is much more general. This template works with all ranges.
Besides range-for, you could consider avoiding the loop entirely (works pre C++20):
auto print = [](auto elm) {
std::cout << elm;
}
std::for_each_n(arr, sz, print);
I recommend this if you don't have C++20, cannot have boost / ranges / GSL libraries for some reason, and cannot have a template.
yes, you can. Just pass the array by reference to a template function:
#include <iostream>
using namespace std;
template <size_t N> void foo(int (&arr)[N])
{
for (auto i:arr)
cout << i << " ";
}
int main()
{
int array[] = { 5, 17, 3452, 546546, 756756, 75675, 756753, 345, 53};
foo(array);
return 0;
}
And the real answer:
int made[] = {10 , 2 ,15};
std::for_each(std::begin(made),std::end(made),[=](auto x){ std::cout << x << std::endl; });
You can parallelize std::for_each with say std::execution::par.
With function code will be:
#include <iostream>
#include <vector>
#include <execution>
void f(int (&made)[3])
{
std::for_each(std::begin(made),std::end(made),[=](auto x){ std::cout << "and then " << x << std::endl; });
}
int main(int argc , char *argv[])
{
int made[] = {10 , 2 ,15};
f(made);
}
This question already has answers here:
How do I print out the arguments of a function using a variadic template?
(3 answers)
Closed 2 years ago.
Is there a way to create a function or a macro in C++ that you can use like Python?
What i mean is a function like:
print(i); // i is an integer.
print(i, s); // i is an integer, s is a std::string. They are separated by a white space.
A function that takes in a number of arguments, then just prints them out regardless of the types.
Use streams:
std::cout << i << ' ' << s << '\n';
For more complex formatting consider fmt, it supports the syntax for python's str.format as well as printf style formatting (but typesafe).
If you are allowed to use C++17, you can do it using fold-expression, like this:
#include <iostream>
template<class ...Args>
void print(const Args &...args) {
auto seq_started = false;
auto print_impl = [&](auto &value) mutable {
if (seq_started) {
std::cout << " " << value;
} else {
seq_started = true;
std::cout << value;
}
};
(print_impl(args), ...);
}
int main() {
print("foo", 10, "bar", 20, "baz");
return 0;
}
I assume that the question is about general solution and that print is just an example.
The answer is: yes, with a combination of overloads and templates. First you setup functions per type:
void print_impl(const std::string& arg) {
std::cout << arg;
}
void print_impl(int arg) {
// Note: this is an example. Of course cout already
// does that for us with simple
// std::cout << arg;
print_impl(convert_to_string(arg));
}
// cout already has lots of overloads, we can take
// advantage of that if needed:
template<class TArg>
void print_impl(TArg&& arg) {
std::cout << std::forward<TArg>(arg);
}
then templates:
template<class TArg>
void print(TArg&& arg) {
print_impl(std::forward<TArg>(arg));
}
template<class TArg1, class ... TArgs>
void print(TArg1&& arg1, TArgs&& ... args) {
print_impl(std::forward<TArg1>(arg1)); // <-- print first argument
print_impl(" "); // <-- insert separator, requires const std::string& overload
print(std::forward<TArgs>(args)...); // <-- recursive call
}
In the code above you can replace calls to print_impl with calls to std::cout << operator directly, if needed. Although I would keep print_impl because it is a nice layer above std::cout in case you want to replace it in the future.
Then you can use it similar to Python:
int main()
{
print("test");
print(1, 2, "foo");
print("foo", 1, 2);
return 0;
}
So I am currently a student and have run into the following exercise:
Write a function that prints the elements in an array. The array is sent to the function by argument. If this argument is not an array, an exception of type invalid_argument must be thrown. Test the function in the main() function.
So my code is currently as follows:
#include <iostream>
#include <exception>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::invalid_argument;
using std::string;
template<class T>void printArray(T arr){
try{
arr.size();
}
catch(...){
for (int i=0; i < sizeof(arr); i++){
cout << arr[i] << endl;
}
}
throw invalid_argument("Argument not of type array");
};
int main(){
string arrChars[5] = {"1", "2", "3", "John", "5"};
string s = "Jack";
try{
printArray(arrChars);
}
catch(invalid_argument &e){
cout << "Error: " << e.what() << endl;
}
return 0;
}
This is after already trying other options such as:
template<class T>void printArray(T arr[]){
...
}
Which doesn't allow the program to run either as I cannot pass any arguments to the printArray() function that are not arrays.
My plan with the code is to swap out arrChars and s as the arguments to printArray() in order to determine success off the program.
If this argument is not an array, an exception of type invalid_argument must be thrown.
That's... a weird thing to want to do in C++. Typically, we'd go for "if this argument is not an array, the code should not compile." But hey, we can do that too. Just write one function overload that takes an array, and one that takes anything:
template <typename T, size_t N>
void printArray(const T (&arr)[N]) {
// print array of size N here
}
template <typename T>
void printArray(const T& ) {
throw invalid_argument("Argument not of type array");
}
Try something like this
#include <iostream>
#include <type_traits>
#include <stdexcept>
#include <vector>
template <class T>
void printArray( const T &a )
{
if ( !std::is_array<T>::value ) throw std::invalid_argument("Argument not of type array");
for ( const auto &x : a ) std::cout << x << std::endl;
}
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
try
{
printArray( a );
printArray( v );
}
catch ( const std::invalid_argument &e )
{
std::cout << e.what() << std::endl;
}
}
The program output is
0
1
2
3
4
5
6
7
8
9
Argument not of type array
"Write a function that prints the elements in an array"
When you say "array", Are we talking about C[] array or std::array.
Assuming that you are talking about std::array you could write a single template method expecting one argument of any type.
If it is std::array that you are talking about then its totally understandable and possible. Here is a possible solution.
Use a dynamic_cast or typeid to check the type of the argument received.
template <typename T> void printArray(const T& arrayArgument) {
if (std::array<int>& test == dynamic_cast<std::array<int>&>(arrayArgument))
{/* do whatever */ }
}
or
if(typeid(arrayArgument) == typeid(std::array<int>))
Find more information on dynamic_cast and typeid in the following post.
C++ dynamic_cast vs typeid for class comparison
And if you are thinking of using C[] arrays then this post might help you rethink.
Container Classes over legacy C[] arrays
#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?
As #Nik pointed out, I could obviously pass in an array, but there is no real fun with that! I am trying to do this just for learning - to see if this is even possible in C++.
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.
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.
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;
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
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);
I need to use a list of elements of the same type as a template argument so I'm using a vector but I'm not sure how to make this work
#include <iostream>
#include <cstdint>
#include <vector>
template <uint8_t VAL>
void foo()
{
std::cout << "__" << std::endl;
};
template <>
void foo<3>()
{
std::cout << "OK" << std::endl;
};
int main()
{
std::vector<uint8_t> v = { 2, 4, 5, 2, 3, 55 };
for (auto &k : v) {
foo<k>();
}
return (0);
}
the compiler basically complains about k not being a constant expression, the problem is that I have no idea about how to modify this to make this work, I need some data structure to iterate on, so I need to keep the vector, I need a template to simplify my life, so the more I see this the more I feel trapped in an infinite loop.
You could use a variadic template to get rid of actually storing your list in a vector, so you'd just pass the values directly to the variable function template:
#include <iostream>
void print(int t) {
static char const *s [] = { "__", "OK" };
std::cout << s[t == 3];
}
void print() {}
template<typename... Args>
void print(int n, Args ... args) {
print(n);
print(args...);
}
int main() {
print(2, 4, 5, 2, 3, 55);
}
Result:
________OK__
As you can see, however, this still has to evaluate equality to 3 at run-time. I hesitate to say it can't be done with template specialization, but at least offhand, I don't see how to do it, if its possible.
You shouldn't be using a template if whatever needs to go <here> cannot be deduced on compile time trivially. In this case, k is not a constant expression, so you cannot use it as a template argument.
Templates are not a magic hammer. They have a lot of use-cases, but you can't use them for absolutely everything.
In this particular snippet of code, foo should be defined as void foo(uint8_t).
yes, infact my problem is how to turn that vector into a constant-compile-time set of values, the real problem it's not really about templates.
You might be able to pull this off using variadic templates. Instead of using the vector, you would use the integral constants directly in a variadic template (foo<2, 4, 5, 2, 3, 55>).
I'm not very keen on them, so this'll take a while.
edit: Jerry beat me to it.
If you really want a way to iterate over a compile-time constant list of integral values:
#include <iostream>
#include <cstdint>
template <uint8_t VAL>
inline void foo()
{
std::cout << "__" << std::endl;
}
template <>
void foo<3>()
{
std::cout << "OK" << std::endl;
}
template <uint8_t... Values>
struct FooHelper {
static void foo_all() {
}
};
template <uint8_t First, uint8_t... Rest>
struct FooHelper<First, Rest...> {
static void foo_all() {
foo<First>();
FooHelper<Rest...>::foo_all();
}
};
template <uint8_t... Values>
void foo_all()
{
FooHelper<Values...>::foo_all();
}
int main()
{
foo_all<2, 4, 5, 2, 3, 55>();
}
Although I honestly don't see the use case for it.
The compiler has no possibility to infer the possible values for k at compile time, so I can't see how this could work ?
Nope, that won't work for non-constant expressions. Just make it a plain old function:
#include <iostream>
#include <cstdint>
#include <vector>
void foo(uint8_t VAL)
{
if(VAL == 3)
std::cout << "OK" << std::endl;
else
std::cout << "__" << std::endl;
};
int main()
{
std::vector<uint8_t> v = { 2, 4, 5, 2, 3, 55 };
for (auto &k : v) {
foo(k);
}
return (0);
}