473,396 Members | 1,683 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

template< ARR1, ARR2, VAL > doit( ARR1 < ARR2 > )

63
yeah i know that the title is not really a question - sorry - i fail to put my question into one sentence so i put it into a storry:

background is i am using two different 'ARRAY's in my code.
(ie. things with access in constant time via operator[] )
namely std::vector and something from another library. but, still i do mostly the same things one both so, a while ago i decided to implement most in templates so i can easily change between them.

so e.g. i have things like
Expand|Select|Wrap|Line Numbers
  1. inline unsigned int size(const ThirdPartyArray<T>& arr ){
  2.   return static_cast<unsigned int>( arr.getSize() );
  3. }
  4. inline unsigned int size(const std::vector<T>& arr ){
  5.   return arr.size();
  6. }
which wraps the different methods to determine the size and allows me to do something like that:

Expand|Select|Wrap|Line Numbers
  1. template< typename ARRAY, typename VAL >
  2. unsigned int doit(ARRAY& arr, VAL v){
  3. ...
  4. }

however i would want to also work on multidimensional arrays in that way
Expand|Select|Wrap|Line Numbers
  1. template< typename ARR1, typename ARR2, typename VAL>
  2. void doit(ARR1 < ARR2 >& arr, VAL v){
  3.   for ( unsigned int i=0; i < size(arr); i++ ){
  4.     doit(arr[i],v);
  5.   }
  6. }
but my compiler instructs me that this is obviously not the right way to implement that. (complains on the first '<' in 'void doit( ARR1 <'.

Can someone point me in the right direction? or is that just not possible with templates? or is it not possible to understand my question?
Mar 11 '09 #1
9 1791
weaknessforcats
9,208 Expert Mod 8TB
Probably all you need is:
Expand|Select|Wrap|Line Numbers
  1. template<typename T, typename VAL>
  2. void doit(T* arr, VAL v){ 
  3.   for ( unsigned int i=0; i < size(arr); i++ ){ 
  4.     doit(arr[i],v); 
  5.   } 
All arrays are one dimensional (read this http://bytes.com/topic/c/insights/77...rrays-revealed. At the end of the article is an example that's close to what you are asking for.

You would need arguments for each dimension size.

Then you iterate the multidimensional array using a series of nested loops.
Mar 11 '09 #2
jabbah
63
All arrays are one dimensional
ok, agreed. a matter of terminology right?! so i shall call these beasts arrays of arrays or the like.

read this ...
mhm no i dont really see how that relates to my problem with the templates. maybe using the word 'array' is missleading. Im not talking about c-style arrays like int[8] but rather meant it as a general term for constant-time-random-access ahm ... things. (and within the class of such things i clearly prefer things that have an understanding about their own size, like std::vector, unlike c-style arrays) Also Im not necessarily facing 'matrix'-like things, ie the vectors in the vector may be of different size.


@weaknessforcats
No, didnt work for me. Here a compilable example (i only changed from pointer to reference in your proposal)
Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4.  
  5. template< typename T >
  6. inline unsigned int size(const std::vector<T>& arr )
  7. {
  8.     return arr.size();
  9. }
  10.  
  11. // for array of val
  12. template< typename ARRAY, typename VAL >
  13. void doit(ARRAY& arr, VAL v)
  14. {
  15.     for ( unsigned int i = 0 ; i < size(arr); i++ )
  16.     {
  17.         arr[i] = v;
  18.         cout << arr[i] << " ";
  19.     }
  20.     cout << "\n";
  21. }
  22.  
  23. // for array of array
  24. template<typename ARRAY, typename VAL>
  25. void doit(ARRAY& arr, VAL v)
  26.     for ( unsigned int i=0; i < size(arr); i++ ){ 
  27.         doit(arr[i],v); 
  28.     } 
  29. }
  30.  
  31. void main_vecvectemplate()
  32. {
  33.     cout << __FUNCTION__ << "\n";
  34.  
  35.     std::vector<double> v(3);
  36.  
  37.     doit(v,0.0);
  38.  
  39.     std::vector< std::vector<double > > v2;
  40.     v2.push_back( std::vector<double>(2) );
  41.     v2.push_back( std::vector<double>(3) );
  42.  
  43.  
  44.     // raises an error because the compiler tries to instantiate doit for array of val and complains about
  45.     // binary = with right hand side double and
  46.     // binary << for vector
  47.     doit(v2, 1.1);
  48.  
  49.     cout << __FUNCTION__ << " done\n";
  50. }
  51.  
I guess i could rename doit for array of val to ... doit_for_array_of_val or doitm or whatever. Im only wondering whether there is a more elegant solution. My idea with
Expand|Select|Wrap|Line Numbers
  1. template< typename ARR1, typename ARR2, typename VAL>
  2. void doit(ARR1 < ARR2 >& arr, VAL v)
was an attempt to kind of specialize doit, since doit for array of array is one special case and doit for array of val is another special case, where i would hope the compiler is able to deduce which one is appropriate
Mar 12 '09 #3
weaknessforcats
9,208 Expert Mod 8TB
You keep using the word array and you mention C arrays as though they were different from C++ arrays, which
they are not.

An array means a specific thing: A collection of elements continguous in memory.

You use the [] to define the number of elements, like:

Expand|Select|Wrap|Line Numbers
  1. int arr[5];
  2.  
for an collection of 5 contiguous integers.

This:
Expand|Select|Wrap|Line Numbers
  1. int arr1[5][3];
  2.  
still has 5 elements not 15!. Each element is an array of 3 ints.

When you iterate these arrays, you iterate over 5 elements each time. In the case of the second array, each element may require an inner iteration over 3 ints.

When these are passed to functions, only the name of the array is passed.
The name of the array is always the address of element 0. In the
first case the name of the array is the the address of arr[0], an int. So your
function needs an int* argument. In the second case, the address of element 0 is the address of an array of 3 int so your function needs and int (*)[3] argument.

That means a) you can't generalize arrays and b) you always have to specify the
number of elements.

The only workaround is to pass in the first case &arr[0] (address of an int) and
& arr1[0][0] (address of an int). Then your function needs and int* argument
for the array plus a) the number of ints plus in the second case b) the number
of 3-integer arrays.

You will still need two functions since the number of arguments varies.

Passing arrays to functions incurs decay of array (Google this). It means
when viewed from inside the function the array structure has been lost since all you have is an address.

Finally, a vector is required to implement an array. You are using vectors.
Therefore, you are using arrays and have to follow the rules of arrays.

Just because the vector is a class does not change its internal implementation.
All it does is provide a sets of methods to control the array, which you would have to write anyway to control an array you declared out in public. You still have access to the array:
Expand|Select|Wrap|Line Numbers
  1. vector<int> v(5);
  2. v[0] = 3;
  3. int* ptr = &v[0]; //address of the 3
  4.  
Now you can bypass the vector methods and work woth the array like you did in C.

In your doit example, you handle the various cases by overloading doit. Call it
with an int* and an int for the number of elements and the compiler will call the
doit with int* and int arguments. Call it with and int* and two arguments for the
two dimensions and the compiler will call that doit. From the caller's viewpoint,
doit has been generalized. It works with either two or three arguments. That fact
that there are two functions is irrelevant. Like the Wizard of Oz said "Pay no
attention to the man behind the curtain".
Mar 12 '09 #4
jabbah
63
phew! I do honestly appreciate the effort you put up to try and help me but man we are really drifting apart here!!

yes I do know that

# C arrays are not different from C++ arrays
# an array is a collection of elements continguous in memory
# You use the [] to define ...
# int arr1[5][3] has 5 elements not 15
# The name of the array is always the address of element 0
# Passing arrays to functions incurs decay of array
# a vector is implement via an array. im using vectors = im using arrays

the most relevant difference between array and vector in my opinion is that a vector knows about its size and i can truely forget about the fact that there is an array living inside of the vector. this really enables me to not pay any more attention to the man(array) behind the curtain(vector)!

Yes I could - bypass the vector methods and work with the array like I did in C. - but I do desperately NOT want to!

I do understand that IF i would be using an int* and overloading then the signatures of the two doit's would differ:
# doit(int* arr, int dim)
# doit(int* arr, int dim1, int dim2)
and that would work.

The point is that
a) I dont want to use arrays, since they offer no benefit over vector (but the contrary!)
b) I can not use doit(int* arr, int dim1, int dim2), because I do frequently face the situation that my datastructure is not rectangular, but like in the example of
Expand|Select|Wrap|Line Numbers
  1. std::vector< std::vector<double > > v2;
  2. v2.push_back( std::vector<double>(2) );
  3. v2.push_back( std::vector<double>(3) );
the 'rows' in the 'matrix' v2 do not all have the same number of entries.


uff.

Maybe I really caused this missunderstanding by my use of the word array - the problem is that im really running out of words here. so let me propose the following notation

# c-array
denotes datastructures like
int[3] a;
as they occur in C/C++ programming language

# vector
denotes the datastructure provided by STL: std::vector<>

# array
denotes the concept of a datastructure that allows constant time access to a random element. That concept occurs all through out computer science and i guess any selfrespectable programming language provides something like that.
c-array's and vector's are examples of that. just like eg java.util.Vector

From now on I will strictly stick to that notation.

So im trying to come back to my question.

Im using std::vector and I would want to provide functions that perform some operation on all elements of a vector<int> or on all elements of vector<vector<int> >.
I have achieved that by using different names: doit and doitm
Expand|Select|Wrap|Line Numbers
  1. // for array of val
  2. template< typename ARRAY, typename VAL >
  3. void doit(ARRAY& arr, VAL v)
  4. {
  5.     for ( unsigned int i = 0 ; i < size(arr); i++ )
  6.     {
  7.         arr[i] = v;
  8.         cout << arr[i] << " ";
  9.     }
  10.     cout << "\n";
  11. }
  12.  
  13. // for array of array
  14. template<typename ARRAY, typename VAL>
  15. void doitm(ARRAY& arr, VAL v)
  16.     for ( unsigned int i=0; i < size(arr); i++ ){ 
  17.         doit(arr[i],v); 
  18.     } 
  19. }
  20.  
Im wondering whether template specialization would offer a way to use the name doit for both functions.
Or maybe someone has any other suggestion that is superior to the doit/doitm approach, whereas i dont think a doit(int* arr, int dim)/doit(int* arr, int dim1, int dim2) is superior to doit/doitm.
Mar 12 '09 #5
Savage
1,764 Expert 1GB
Perhaps a recursion can do what you want.

Expand|Select|Wrap|Line Numbers
  1. template<typename ARRAY,typename VAL>
  2. void doit(ARRAY &arr,VAL v,unsigned int dimensions=1)
  3. {
  4.      if(dimensions==1)
  5.      {
  6.         for ( unsigned int i = 0 ; i < size(arr); i++ )
  7.         {
  8.             arr[i] = v;
  9.             cout << arr[i] << " ";
  10.         }
  11.          cout << "\n";
  12.      }
  13.      else
  14.      {
  15.           for ( unsigned int i=0; i < size(arr); i++ ){ 
  16.                doit(arr[i],v,dimensions-1); 
  17.      } 
  18. }
  19.  
Another benefit of this is that it will work for an array of any dimension.
Mar 12 '09 #6
jabbah
63
@Savage
ok. right! i thought that doitm() would work for multiple dimensions (hence m) but of course thats not true! it only works for dim=2. so its rather a doit2().

so yeah this
Expand|Select|Wrap|Line Numbers
  1. void doit(ARRAY &arr,VAL v,unsigned int dimensions=1)
is better than doit/doitm
Mar 13 '09 #7
jabbah
63
now i got it!

i was always thinking along specializations for
doit( ARRAY<WHATEVER>, VALUE ) for multiple dimensions and
doit( ARRAY<VALUE>, VALUE ) for the one-dimensional case

but more appropriate is
doit( ARRAY<WHATEVER>, VALUE ) for any dimension and
doit( VALUE, VALUE ), ie

Expand|Select|Wrap|Line Numbers
  1. template< typename ARRAY, typename VAL >
  2. void set_all(ARRAY& arr, const VAL& val)
  3. {
  4.     for ( unsigned int i = 0 ; i < size(arr); i++ )
  5.     {
  6.         set_all( arr[i], val );
  7.     }
  8. }
  9. template< typename T >
  10. void set_all(T& lhs, const T& rhs)
  11. {
  12.     lhs = rhs;
  13. }
  14.  
Mar 13 '09 #8
weaknessforcats
9,208 Expert Mod 8TB
[quote=jabbah]
# vector
denotes the datastructure provided by STL: std::vector<>
[quote]
Please understand that this datastructure must be an array.

The only reason vector knows the size of the array is becuse it creates the array on the heap for a known number of elements and keeps that number tucked away. You could do the same thing yourself and not use vector at all.
Mar 13 '09 #9
jabbah
63
Please understand that this datastructure must be an array.
i do.

The only reason vector knows the size of the array is becuse it creates the array on the heap for a known number of elements and keeps that number tucked away.
ok.

You could do the same thing yourself and not use vector at all.
ok.


you have helped me greatly in the past weaknessforcats. in more than one occasion! this time it seems we dont even manage to talk about the same thing. thanks anyway!
Mar 13 '09 #10

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Vijay singh | last post by:
Hi wonder if anybody can clear by doubt XML file : <score id="1"> <film>A Little Princess</film> <composer>Patrick Doyle</composer>
4
by: Grey Plastic | last post by:
I have several classes that all keep track of static data. However, the manner that they keep track of static data is identical, and so I'm using the template<class Child> class Parent { ... };...
1
by: David Lindauer | last post by:
so I see declarations for various template classes and functions which start with: template <int __inst> unfortunately the compiler I use doesn't allow that so I can't experiment... but I am...
5
by: tuko | last post by:
The following snipet gives a linker error. I don't get it... template<class T> class tran { public: public: private: }; template<class T> class matrix {
14
by: SoilMan | last post by:
Consider the following: class xyz { public: template <typename T> void foo(T x) { cout << "foo<T> " << x << endl; }
4
by: Gary li | last post by:
Hi, all I find "template template" class cann't been compiled in VC6 but can ok in Redhat9. I write a test program like as: template< template<class> class T> class A { }; int main() {...
4
by: Grizlyk | last post by:
Hello. Why were base class "typedefs" hidden by template<and explicit usage of them does not work too? Try open only one of the lines in the example below //using Tparent::Tptr; //typedef...
3
by: George2 | last post by:
Hello everyone, I sometimes saw code with template<and followed by a class definition, like, template<class { // class definition
10
by: jason.cipriani | last post by:
Is there any difference between declaring a template parameter as a "typename" or a "class"? E.g. template <class TT f() { } template <typename TT g() { } Thanks, Jason
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.