I know how to pass an array of constant size as a reference, but I want to know that how to pass an array of variable size as a reference to another function. Any help would be much appreciated. Thank you
For example, I have the following code snippet:
void y(int (&arr)[n]) //Gives error
{}
void x(Node * tree, int n)
{
int arr[n];
y(arr);
}
I heard that we can templateize the function and make the size a template parameter but I am unable to do so.
Simple: don't. Use std::array or std::vector instead:
int get_max(std::vector<int> & vec) {//Could use const& instead, if it doesn't need to be modified
int max = std::numeric_limits<int>::min();
for(int & val : vec) {if(max < val) max = val;
return max;
}
int get_max(std::array<int, 20> & arr) {//Could use const& instead
int max = std::numeric_limits<int>::min();
for(int & val : arr) {if(max < val) max = val;
return max;
}
If you want this to work for any std::array or any std::vector, you can template them like so:
template<typename T>
T get_max(std::vector<T> const& vec) {
if(vec.size() == 0) throw std::runtime_error("Vector is empty!");
T const* max = &vec[0];
for(T const& val : vec) if(*max < val) max = &val;
return *max;
}
template<typename T, size_t N>
T get_max(std::array<T, N> const& arr) {
static_assert(N > 0, "Array is empty!");
T * max = &arr[0];
for(T & val : arr) if(*max < val) max = &val;
return *max;
}
Your code should now look like this to compensate:
void y(std::vector<int> & arr) //Can be const& if you don't need to modify it.
{}
void x(Node * tree, int n)
{
std::vector<int> arr(n); //Will initialize n elements to all be 0.
y(arr);
}
This answer is to illustrate how to work with VLA in C++ when passing it as a function parameter.
In c99, the syntax allows you to pass the size of the array as a parameter to the function, and use the function parameter to declare the size of the VLA:
void y (int n, int (*arr)[n])
{}
void x (int n)
{
int arr[n];
y(n, &arr);
}
C++ uses "function name mangling" as a technique to encode the parameter types accepted by the function into the function name to support function overloading. However, in GCC, since VLA is not a C++ supported feature, there is no mangling convention for it. One could argue this is a G++ bug (or incomplete support of the VLA extension), but it is what it is. To mimic the pass by reference, accept the decayed pointer as the parameter, and cast it to a reference to the VLA.
void y(int n, int *x)
{
int (&arr)[n] = reinterpret_cast<int (&)[n]>(*x);
}
void x(int n)
{
int arr[n];
y(n, arr);
}
I have verified this works for GCC 4.8.
Xirema already mentioned how to resolve this using std::vector/std::array.
I don't know your exact case, so will just describe another options, despite the fact, that std::vector/std::array is the best.
Pointers option
Here you have believe, that arr and n arguments of y are consistent. And handle arr size manually.
void y(int * arr, const int n) {}
void x(Node * tree, int n) {
int arr[n];
y(arr, n);
}
Templates option
This will work, howether it will instantiate 2 templates on each new N value.
template <size_t N>
void y(int (&arr)[N]) {}
template <size_t N>
void x(Node * tree) {
int arr[N];
y<N>(arr);
}
i need a way to initialize const elements of an array for the program i am currently working on.
The problem is that i have to initialize these elements with a function, there is no way to do it like this:
const int array[255] = {1, 1278632, 188, ...};
because its alot of data i have to generate.
What i tried is to memcpy data to the const int's but that can't work and hasn't worked.
const int array[255];
void generateData(){
for(int i = 0; i < 255; i++) {
initializeSomehowTo(5, array[i]);
}
}
I hope you understand what i am trying, sorry if i doubled the question, i must have overlooked it.
How about this?
#include <array>
typedef std::array<int, 255> Array;
const Array array = generateData();
Array generateData(){
Array a;
for(int i = 0; i < a.size(); i++) {
initializeSomehowTo(a[i]);
}
return a;
}
The easiest approach is to get the filled array from a function and use that to initialize your const (or constexpr) object. However, built-in arrays can't be copied but std::array<T, N> be:
std::array<T, 255> array = initializeData();
If you need a built-in array, I can imagine initializing a static member of a class (template, actually) where the index is expanded from indices expanded from an std::make_index_sequence<255> and used as positional argument in the array, i.e., something along these lines:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
int some_function(std::size_t i) { return i; }
template <typename> struct initialized_array_base;
template <std::size_t... I>
struct initialized_array_base<std::index_sequence<I...>> {
static const int array[sizeof...(I)];
};
template <std::size_t... I>
int const initialized_array_base<std::index_sequence<I...>>::array[sizeof...(I)]
= { some_function(I)... };
struct initialized_array
:initialized_array_base<std::make_index_sequence<256>> {
};
int main() {
std::copy(std::begin(initialized_array::array),
std::end(initialized_array::array),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
You can create a writable array, initialize it, and, then, create a const reference to it.
int arry[255];
void generateData(){
for(int i = 0; i < 255; i++) {
initializeSomehowTo(5, arry[i]);
}
}
const int (&array)[255] = arry;
I have the following code which could not be complied.
using namespace std;
void f(int);
template<typename T1, size_t N>
void array_ini_1d(T1 (&x)[N])
{
for (int i = 0; i < N; i++)
{
x[i] = 0;
}
}
What is the proper way to pass the array if the main is something like below.
int main()
{
int a;
cin >> a;
int n = a / 4;
f(n);
return 0;
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
error: no matching function to call to array_ini_1d..............
The problem is that variable size arrays are not supported by c++, and is only supported as compilers extension. That means, the standard doesn't say what should happen, and you should see if you can find in compiler's documentation, but I doubt that such corner cases are documented.
So, this is the problem :
int arr[n];
The solution is to avoid it, and use something supported by c++, like for example std::vector.
I don't think the compiler can deduce the size of a variable-length array in a template. Also, don't forget to forward declare f before you use it. Variable-length arrays are a GCC extension and you should get a warning regarding their use.
You may declare your function like this:
template <typename A, size_t N> void f(A a[N]) {
for(size_t i = 0; i < N; i++)
cout << a[i];
}
However, the problem is that when you call the function, the compiler won't deduce the template parameters, and you will have to specify them explicitly.
char arr[5] = {'H', 'e', 'l', 'l', 'o'};
int main()
{
//f(arr); //Won't work
f<char, sizeof(arr)/sizeof(arr[0])>(arr);
cout << endl;
return 0;
}
Unfortunately, that ruins the very idea...
UPD: And even that code does NOT work for an array that has variable length, for the length is calculated at runtime, and the template parameters are defined at compilation time.
UPD2: If using std::vector you may create it initialized:
vector<int> arr(n, 0);
Or you may fill it with fill from <algorithm> when needed:
std::fill(arr.begin(), arr.end(), 0);
As you use Variable length array (VLA) (compiler extension), compiler cannot deduce N.
You have to pass it by pointer and give the size:
template<typename T>
void array_ini_1d(T* a, std::size_t n)
{
for (std::size_t i = 0; i != n; ++i) {
a[i] = 0;
}
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
Or use std::vector. (no extension used so). Which seems cleaner:
template<typename T>
void array_ini_1d(std::vector<T>& v)
{
for (std::size_t i = 0, size = v.size(); i != n; ++i) {
a[i] = 0; // or other stuff.
}
}
void f(int n)
{
std::vector<int> arr(n); // or arr(n, 0).
array_ini_1d(arr);
}
Template parameters must be resolved at compile-time.
There is no way that a function template with parameter size_t N can match any sort of array or other container whose size comes from a run-time input.
You will need to provide another version of the array_1d_ini which does not have the size as a template parameter.
template<typename T, size_t N>
void f(T* a)
{
/* add your code here */
}
int main()
{
int a[10];
f<int, 10>(a);
return 0;
}
Playing with templates, I implemented this one for iterating arrays:
template<class T, size_t size>
void iterate(T(&arr)[size], void(*fn)(T&)) {
for(size_t i=0; i<size; ++i) fn(arr[i]);
}
So I could iterate arrays like this
void printn(int& n) {
printf("%d\n",n);
}
int a[] = {3,-4,6,2};
iterate(a,printn);
Then I realized that I also need const iterator, so the first bad idea was to code
template<class T, class U, size_t size>
void iterate(T(&arr)[size], void(*fn)(U&)) {
for(size_t i=0; i<size; ++i) fn(arr[i]);
}
I know it is bad, but I wonder why this behavior:
void printn(int& n); // works
void printn(const int& n); // also works
void printn(short& n); // type mismatch
void printn(const short& n); // works
There is also an issue with lambdas:
iterate(a,[](int& n) { printf("%d\n",n); }); // type mismatch
So the question is Why the type mismatches and how to solve them?
I use 32bit MinGW 4.8.1 with -std=C++11 option.
I need to implement a generic algorithm that can operate on a matrix regardless of its representation. It could be a C-style 2D array, a vector of vectors or an arbitrary user class (which does not necessarily provide a subscript operator).
An obvious solution could look like this:
template<typename M>
void func(M& mat, int cols, int rows)
{
for(int j = 0; j < rows; ++j)
for(int i = 0; i < cols; ++i)
doSomething(elem(mat, i, j));
}
...where the user would have to provide an overload of 'elem' that operates on his matrix type. The problem with this approach is that this overload would need to be declared before 'func' for the code to compile, and not just before the template instantiation. Is there a way around this problem that does not involve an ugly function signature or forcing the user to write a wrapper class and other boilerplate code?
I have tried it and found a possible solution after my first comment. So Just including the declaration into the generic function, it works! See my example code below.
The point finally seems to be that the templetized code doesn't get the declaration of elem() done in the non-templetized code.
It's after the definition of the template, but before of its first instantiation, so, to my knowledge/understanding, it should be enough.... but my complier (gcc 4.8.2) complains as well. I'm sure to have used this feature many times with templetized methods and classes.
It seems really strange to me and possibly a bug (#Potatoswatter: can you give a reference to the bug - see if this match?).
EDITED: Finally understood. Still studying C++11 Stroustrup's! It works as intended in the standard. I give here some pointers - excerpts.
The first important idea is suggested in 23.3.2 (Templates, Error detection): Syntax error are checked in definitions before they are used in the first instance. Sure they are, but though that it was just defined later. But: "a name used in a template definition must either be in scope or in some reasonably obvious way depend on a template parameter". This is clear enough already now, but most important is the rationale behind this idea.
It's explained in great detail in 26.3 (Instantiation [of templates!], Name Binding): "Define template functions to minimize dependencies on nonlocal information. The reason is that a template will be used to generate functions and classes based on unknown types and in unknown contexts. Every subtle context dependency is likely to surface as a problem for somebody...".
After reading it - I'm still asking myself why I haven't thought to such an important difference, with respect to the controlled environment present within a generic class!!
Explanation go on (pages 745-758!) and the mechanism for the resolution is explained especially in 26.3.2 (Point-of-definition Binding) and 26.3.3 (Point-of-instantation Binding):
"When the compiler sees a template definition, it determines which names are dependent (26.3.1). If a name is dependent, looking for its declaration is postponed until instantiation time (26.3.3)."
"Names that do not depend on a template argument are treated like names that are not in templates; they must be in scope (6.3.4) at the point of definition".
That's stoned. elem() must be declared before it's used in the template definition - it is treated like names that are not in templates.
I agree with #Potatoswatter and others. This is probably the less elegant solution, since it restricts to the use of an external function, no functors, no lambdas.
On the other side, it addresses the problem (thought it was a workaround initially... no, it's just how it's intended to work!) of the OP.
#include <iostream>
using namespace std;
template<typename M, typename R>
void func(M mat, int cols, int rows)
{
// with this declaration it works.
R &elem(M, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
elem(mat, i, j) += 1; // +=1 is just your "doSomething()"
}
}
}
template<typename M, typename R>
void show(M mat, int cols, int rows)
{
R &elem(M, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
if (j>0) cout << ", ";
cout << elem(mat, i, j);
}
cout << endl;
}
}
float &elem(float *m, int i, int j) {
return m[i*3+j];
}
float &elem(float m[3][3], int i, int j) {
return m[i][j];
}
int main(int argc, char **argv) {
float mat1d[9] = {1,2,3,4,5,6,7,8,9};
float mat2d[3][3] = {1,2,3,4,5,6,7,8,9};
func<float*, float>(mat1d, 3, 3);
show<float*, float>(mat1d, 3, 3);
func<float(*)[3], float>(mat2d, 3, 3);
show<float(*)[3], float>(mat2d, 3, 3);
}
Trying to use references as in your question I've got slightly crazy before understanding that mixing them with statically declared sizes, let things much more stuck. I include it here because I have lost quite some time trying to get around this:
#include <iostream>
using namespace std;
template<typename M, typename R>
void func(M &mat, int cols, int rows)
{
R &elem(M&, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
elem(mat, i, j) += 1; // +=1 is just your "something"
}
}
}
template<typename M, typename R>
void show(M &mat, int cols, int rows)
{
R &elem(M&, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
if (j>0) cout << ", ";
cout << elem(mat, i, j);
}
cout << endl;
}
}
float &elem(float (&m)[9], int i, int j) {
return m[i*3+j];
}
float &elem(float (&m)[3][3], int i, int j) {
return m[i][j];
}
int main(int argc, char **argv) {
float mat1d[9] = {1,2,3,4,5,6,7,8,9};
float mat2d[3][3] = {1,2,3,4,5,6,7,8,9};
func<float[9], float>(mat1d, 3, 3);
show<float[9], float>(mat1d, 3, 3);
func<float[3][3], float>(mat2d, 3, 3);
show<float[3][3], float>(mat2d, 3, 3);
}
NOTE: in this way elem() is a function, included at link time. I think that's not what you want, but then you can get around it making a functor of all the stuff.
The easiest solution is that a subscript operator should be mandatory.
You are ok to force the user to declare a elem function, but you don't want to force him to overload a subscript operator. This doesn't make sense to me. Consider the case when he uses an array or a class that already has a subscript operator defined. Why would you force him to define a function that does what the subscript operator already does?
However this is how you do what you want:
template<typename M, typename F>
void func(M& mat, int cols, int rows, F elem)
{
for(int j = 0; j < rows; ++j)
for(int i = 0; i < cols; ++i)
doSomething(elem(mat, i, j));
}
This can be called with references to functions, pointer to functions or lambdas.
Call example with lambda:
func(mat, 5, 5, []->int (int **m, int i, int j) { return m[i][j];});
I haven't test it so I hope there are no syntax errors.
As a middle ground beside that you could have an overload what doesn't receive elem as a parameter and uses the subscript operator.
The problem with this approach is that this overload would need to be declared before 'func' for the code to compile, and not just before the template instantiation.
This sounds like a misunderstanding; it's much stronger than the actual requirement. The overload called by a particular specialization only needs to be declared before the point of instantiation of that specialization, i.e. before whatever non-template call in each translation unit that first leads to your template.
Before the template definition, you only need some function named func; it doesn't need to remotely match the call or to be useable for any purpose. It's just a placeholder to let the parser know that your template is making a function call there. This would do fine:
void elem( struct unused_tag_type ) = delete;
as would this:
void elem();
Below is my attempt towards a minimal running sample to demonstrate the problem, and a solution. I have only been able to produce the problem when functions and data are defined in different namespaces. I think this is the most general case.
Problem (live example):
namespace X { struct A {}; }
namespace Y { // function-style
template<typename T>
void f(T x) { h(x); }
void g() { f(X::A{}); }
void h(X::A) { cout << "Hello, world!" << endl; }
}
Solution (live example):
namespace X { struct A {}; }
namespace Y { // functor-style
template<typename T>
struct H;
template <typename T>
void h(T x) { H<T>()(x); }
template<typename T>
void f(T x) { h(x); }
void g() { f(X::A{}); }
template<>
struct H<X::A>
{
void operator()(X::A) { cout << "Hello, world!" << endl; }
};
}
In words, use a template struct (function object, H) to do the job and a template function (h) only as a wrapper. H can be specialized whenever you like (but in the same namespace). Its general declaration and the declaration of h should appear before the point of instantiation in g().
Limitation (live example): Unfortunately, this does not work if the return type is unknown, that is, if you replace H and h by the most general forms
template<typename... T>
struct H;
template <typename... T>
auto h(T&&... x)
->decltype(H<T...>()(std::forward <T>(x)...))
{ return H<T...>()(std::forward <T>(x)...); }
I've tried and it doens't even work with -std=c++1y without the training return type. But I hope this is not an issue in your case.