I am doing some very basic problems to get familiar with Template Metaprogramming. This one in particular is just to add up the values on the down-right diagonal of a square matrix (indexes of [0,0],[1,1], etc.). I have solved this in many ways with different constexpr functions, but I do not understand why one particular way fails. Code and error message below:
constexpr int DRsum(const int* starter, const size_t size, int itr = 0)
{
if(itr==size-1)
{
return *starter;
}
size_t sum = 0;
sum = *starter;
sum += DRsum(starter+size+1, size, itr+1);
return sum;
}
int main()
{
static const size_t size = 3;
static constexpr const int matrix[][size] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
static constexpr int const* baseptr = &matrix[0][0];
constexpr int sum = DRsum(baseptr, size);
}
The error message is as follows:
main.cpp|69| in constexpr expansion of 'DRsum((& matrix[0][0]), 3u, 0)'|
main.cpp|39| in constexpr expansion of 'DRsum((starter + ((((sizetype)size) + 1u) * 4u)),
((size_t)size), (itr + 1))'|
main.cpp|69|error: '* starter' is not a constant expression|
I am not sure why this is doing this, as I am new to Template Metaprogramming. I made a dummy function to test if the pointer dereference was the issue, and that worked out fine. My guess is that it might have to do with me passing in a pointer rather than a pointer to a constexpr pointer, but I'm not sure. Any help would be appreciated, Thanks.
Also, I have already solved this by means of just passing in the entire structure (just straight up a deep copy) but I would rather know how to pass things by shallow copy or pointer into constexpr functions. Thanks.
A 2D array (matrix) cannot be treated as a 1D array, so starter+size+1 results in undefined behavior. Usually undefined behavior is undefined so the program may work as expected, but when an undefined behavior happens within a structure that requires a constant expression, the program becomes ill-formed thus the compiler emits an error.
I don't think there is a simple fix because there is no well-defined way to access the whole 2D array through starter (even with std::launder), unless you change the signature of DRsum. For example, you can write DRsum as follows:
template <size_t size>
constexpr int DRsum(const int (*starter)[size], int itr = 0)
{
if (itr == size - 1)
{
return (*starter)[itr];
}
size_t sum = 0;
sum = (*starter)[itr];
sum += DRsum(starter + 1, itr + 1);
return sum;
}
then call it like constexpr int sum = DRsum(matrix);.
Related
I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?
You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.
Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.
For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.
In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);
You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.
In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).
Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.
The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.
I have created a one dimensional vector of int, how may I treat it like 2 dimensional one?
While I can write arr[1]; I can't write arr[1][2];
Why I need this:
Instead of defining a vector of vectors [3x5] I defined a vector whose length is 15, so every time I have a function that takes coordinations of a place in matrix I have to call another function which converts those into one dimensional value, which is really annoying.
Assuming you want to treat a 1D array of size N as a 2D array with M columns, then you can write a helper function that computes the 1D index given 2D indexes:
auto in = [M] (int i, int j) { return i * M + j; };
and then use it like this:
arr[in(i,j)];
This is at least preferable to saying arr[i * M + j] everywhere, which is error prone.
Ideally, you would wrap this 1D array into a class that supports 2D indexing.
It seems to me that the best solution is avoid at all the double operator[] and define an at() function that receive two indexes.
Anyway, if you really (really!) want a double operator[] solution, the first one has to return an object with requested data and support the second operator[]
I propose the following skeletal example, where a arr2d (with compile time known dimension) is based over a mono-dimensional std::array.
#include <array>
#include <iostream>
template <typename T, std::size_t Dim1, std::size_t Dim2>
class Arr2d
{
private:
using int_arr_t = std::array<T, Dim1 * Dim2>;
int_arr_t arr{};
public:
struct foo
{
int_arr_t & arr;
std::size_t const i1;
T & operator[] (std::size_t i2)
{ return arr[i1*Dim1 + i2]; }
T const & operator[] (std::size_t i2) const
{ return arr[i1*Dim1 + i2]; }
};
foo operator[] (std::size_t i1)
{ return {arr, i1}; }
foo const operator[] (std::size_t i1) const
{ return {arr, i1}; }
};
int main ()
{
Arr2d<int, 2, 3> a2d;
a2d[1][2] = 3;
std::cout << a2d[1][2] << std::endl;
}
As you can see, the arr2d::operator[] return a foo object containing a reference to the std::array and the first index.
The foo::operator[] complete the job, returning a reference (or a constant reference, according the case) to the right element inside the original std::array.
But, I repepeat: i prefer a couple of at() functions in Arr2d
T & at (std::size_t i1, std::size_t i2)
{ return arr[i1*Dim1 + i2]; }
T const & at (std::size_t i1, std::size_t i2) const
{ return arr[i1*Dim1 + i2]; }
The use of the comma operator was deprecated inside square brackets with C++20. This will in the future enable to write something like m[i, j] for matrix access.
Until then your only chance is to use a member function like at.
A clever and not recommended approach is to have operator[] return some kind of row proxy that has a operator[] on its own to perform the indexing. That is shown here.
Note that storing the row_proxy can lead to dangling pointers which is why operator[]is only implemented for rvalue references.
So I made a function that takes arrays as parameters and I've tried calling the function by passing arrays that have not been defined as variables into said function (like {0,0,0,0}). However, I am given an error which says "too many initializer values."
Say we have a function defined as:
int func(int values[]) {
int average = 0;
for(int x = 0; x < values.size(); x++) {
average += values[x];
}
return average / values.size();
}
And we want to call it without defining an array to pass in like this: func({1,6,7,2});
Is there any way to do something like this or would I have to define an array and pass it into the function that way?
You cannot do that using built-in arrays. The fact that Arrays are neither Assignable nor Copy-able. Also They are not classes so they don't have member functions like size() or they take Initializer-list.
You can achieve that through using std::array if the size is constant or using std::vector if the size if dynamic.
#include <array>
int func(const std::array<int, 5>& values) {
int average = 0;
for (size_t x{}, sz{ values.size() }; x != sz ; ++x)
average += values[x];
return average / values.size();
}
int main() {
auto ret{
func({ 1, 6, 7, 2 })
};
std::cout << ret << std::endl;
}
Also don't mix Unsigned with Signed in calculations like in your loop:
for(int x = 0; x < values.size(); x++) // x is int while values.size() is unsigned int.
int func(const std::array<int, 5>& values): pass by reference to avoid the copy especially if the size is big. Also pass by const as long as the function doesn't intend to change the parameter also another benefit of using const reference is you can pass literals instead of an object.
N.B: I recommend to also to use range-based for because it is really relevant in your example as long as you want to iterate over all the elements and not intending to insert nor to delete elements:
int average = 0;
for (const auto& e : values)
average += e;
Another version of func as #M.M pointed out is to use std::accumalate to do the job for you:
int func(const std::array<int, 5>& values) {
return std::accumulate(values.begin(), values.end(), 0) /
values.size();
}
Using a vector, yes:
#include <vector>
using namespace std;
void f( const vector <int> & v ) {
}
int main() {
f( {1,2,3,4} );
}
Arrays don't work like that. When you pass an array to a function, the address of the first element gets passed like a pointer, and inside the function there is no more information about the size of the array. (Before the compiler itself could infer the size because the array was declared in the scope, but a function can be called from any number of places)
If you want to do something like that you would either have to use a container class, such as a vector, or you could pass a second argument into the function stating the size of the array. Another way is to have some sort of end point in your array, such as is the case with c-strings, for example a null value.
My question is simple, if I have a matrix created on the stack rather than on the heap, such as int matrix[10][10], how can I pass it by reference? Or, pass it in a way that it doesn't pass the whole matrix as argument, but just its pointer or reference, or whatever. I use C++11.
void proc(/*WHAT GOES HERE?*/ matrix, int n){
matrix[n-1][n-1] = 7;
}
int main(){
int matrix[10][10];
proc(matrix, 10);
return 0;
}
You simply need:
// By reference:
void proc_ref(int (&matrix)[10][10]); // first dimension must have a size of 10
// By pointer:
void proc_ptr(int (*matrix)[10], int n); // n is the size of the first dimension
In the first case, matrix will be a reference to an array of 10 array of 10 ints ("reference to int[10][10]"), in the second case matrix will be a pointer to an array of 10 int ("pointer to int[10]").
In both cases you can use it like you want in proc:
matrix[i][j] = 42;
The second version allows passing matrix of various size such as int[14][10] or int[12][10] (as long as the second dimension as a size of 10). It also allows passing dynamically allocated array of array of 10 int:
int (*p)[10] = new int[42][10];
proc_ref (p); // Error
proc_ptr (p, 42); // Ok
int m[24][10];
proc_ref (p); // Error
proc_ptr (p, 24); // Ok
If you want to only allow square matrix declared with automatic storage duration, use the reference versions.
Note: You have to specify the second dimension of your matrix at compile time. If you want to be "generic" you could use a template:
template <size_t N>
void proc (int (&matrix)[N][N]);
Also, if you are using c++11, you should use std::array which is much more convenient while still doing exactly what you want (no dynamic allocation):
template <typename T, size_t N>
using matrix_t = std::array<std::array<T, N>, N>;
template <typename T, size_t N>
void proc (matrix_t<T, N> &matrix) {
matrix[N - 1][N - 1] = 7;
}
int main () {
matrix_t<int, 10> matrix;
proc(matrix);
}
Array might decay to pointer. You can declare the parameter type as a pointer (to array) like:
void proc(int (*matrix)[10], int n){
matrix[n-1][n-1] = 7;
}
Note the dimension won't be reserved when array decaying to pointer, means you might pass int [11][10] to proc() in this case.
If you don't want this, you can declare the parameter type as reference like:
void proc(int (&matrix)[10][10], int n){
matrix[n-1][n-1] = 7;
}
Only int[10][10] could be passed here.
I am trying to learn C++ function templates.I am passing an array as pointer to my function template. In that, I am trying to find the size of an array. Here is the function template that I use.
template<typename T>
T* average( T *arr)
{
T *ansPtr,ans,sum = 0.0;
size_t sz = sizeof(arr)/sizeof(arr[0]);
cout<<"\nSz is "<<sz<<endl;
for(int i = 0;i < sz; i++)
{
sum = sum + arr[i];
}
ans = (sum/sz);
ansPtr = &ans;
return ansPtr;
}
The cout statement displays the size of arr as 1 even when I am passing the pointer to an array of 5 integers. Now I know this might be a possible duplicate of questions to which I referred earlier but I need a better explanation on this.
Only thing I could come up with is that since templates are invoked at runtime,and sizeof is a compile time operator, compiler just ignores the line
int sz = sizeof(arr)/sizeof(arr[0]);
since it does not know the exact type of arr until it actually invokes the function.
Is it correct or am I missing something over here? Also is it reliable to send pointer to an array to the function templates?
T *arr
This is C++ for "arr is a pointer to T". sizeof(arr) obviously means "size of the pointer arr", not "size of the array arr", for obvious reasons. That's the crucial flaw in that plan.
To get the size of an array, the function needs to operate on arrays, obviously not on pointers. As everyone knows (right?) arrays are not pointers.
Furthermore, an average function should return an average value. But T* is a "pointer to T". An average function should not return a pointer to a value. That is not a value.
Having a pointer return type is not the last offense: returning a pointer to a local variable is the worst of all. Why would you want to steal hotel room keys?
template<typename T, std::size_t sz>
T average( T(&arr)[sz])
{
T ans,sum = 0.0;
cout<<"\nSz is "<<sz<<endl;
for(int i = 0;i < sz; i++)
{
sum = sum + arr[i];
}
ans = (sum/sz);
return ans;
}
If you want to be able to access the size of a passed parameter, you'd have to make that a template parameter, too:
template<typename T, size_t Len>
T average(const T (&arr)[Len])
{
T sum = T();
cout<<"\nSz is "<<Len<<endl;
for(int i = 0;i < Len; i++)
{
sum = sum + arr[i];
}
return (sum/Len);
}
You can then omit the sizeof, obviously. And you cannot accidentially pas a dynamically allocated array, which is a good thing. On the downside, the template will get instantiated not only once for every type, but once for every size. If you want to avoid duplicating the bulk of the code, you could use a second templated function which accepts pointer and length and returns the average. That could get called from an inline function.
template<typename T>
T average(const T* arr, size_t len)
{
T sum = T();
cout<<"\nSz is "<<len<<endl;
for(int i = 0;i < len; i++)
{
sum = sum + arr[i];
}
return (sum/len);
}
template<typename T, size_t Len>
inline T average(const T (&arr)[Len])
{
return average(arr, Len);
}
Also note that returning the address of a variable which is local to the function is a very bad idea, as it will not outlive the function. So better to return a value and let the compiler take care of optimizing away unneccessary copying.
Arrays decay to pointers when passed as a parameter, so you're effectively getting the size of the pointer. It has nothing to do with templates, it's how the language is designed.
Others have pointed out the immediate errors, but IMHO, there are two
important points that they haven't addresses. Both of which I would
consider errors if they occurred in production code:
First, why aren't you using std::vector? For historical reasons, C
style arrays are broken, and generally should be avoided. There are
exceptions, but they mostly involve static initialization of static
variables. You should never pass C style arrays as a function
argument, because they create the sort of problems you have encountered.
(It's possible to write functions which can deal with both C style
arrays and std::vector efficiently. The function should be a
function template, however, which takes two iterators of the template
type.)
The second is why aren't you using the functions in the standard
library? Your function can be written in basically one line:
template <typename ForwardIterator>
typename ForwardIterator::value_type
average( ForwardIterator begin, ForwardIterator end )
{
return std::accumulate( begin, end,
typename::ForwardIterator::value_type() )
/ std::distance( begin, end );
}
(This function, of course, isn't reliable for floating point types,
where rounding errors can make the results worthless. Floating point
raises a whole set of additional issues. And it probably isn't really
reliable for the integral types either, because of the risk of overflow.
But these are more advanced issues.)