Template Argument error (likely simple)

Hello, I'm quite new to C++, but I have spent too much time "programming" in Mathematica (no scoffing too much, it's actually quite powerful for my purposes).

I am trying to use some header-defined functions from the NIST TNT project, and I'm having trouble with the template for 2D arrays. i.e. When I try to run:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include "tnt.h"
#include "tnt_array1d.h"
#include "tnt_array2d.h"
#include "tnt_math_utils.h"
#include "jama_eig.h"
#include <algorithm>
#include <cmath>
using namespace TNT;
using namespace std;
using namespace JAMA;


   int main()
{
    Array2D< double > A(2,2, 1.0);    /* create MxN array; all ones */

    cout << A <<endl;
    
    Eigenvalue.getV(A);

}


I get the error:
error: missing template arguments before '.' token

I am embarrassed to say how much time I've spent on this before asking for help. I think I'm doing something wrong with how I create the array, but I'm not sure how to fix it. I've looked about online, but none of the similar error's fixes worked for me.

Please, show the template parameter declaration for Array2D and the declaration of the corresponding constructor.
Here is the tnt_array2d header file containing everything about Array2D:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#ifndef TNT_ARRAY2D_H
#define TNT_ARRAY2D_H

#include <cstdlib>
#include <iostream>
#ifdef TNT_BOUNDS_CHECK
#include <assert.h>
#endif

#include "tnt_array1d.h"

namespace TNT
{

template <class T>
class Array2D 
{


  private:



  	Array1D<T> data_;
	Array1D<T*> v_;
	int m_;
    int n_;

  public:

    typedef         T   value_type;
	       Array2D();
	       Array2D(int m, int n);
	       Array2D(int m, int n,  T *a);
	       Array2D(int m, int n, const T &a);
    inline Array2D(const Array2D &A);
	inline operator T**();
	inline operator const T**();
	inline Array2D & operator=(const T &a);
	inline Array2D & operator=(const Array2D &A);
	inline Array2D & ref(const Array2D &A);
	       Array2D copy() const;
		   Array2D & inject(const Array2D & A);
	inline T* operator[](int i);
	inline const T* operator[](int i) const;
	inline int dim1() const;
	inline int dim2() const;
     ~Array2D();

	/* extended interface (not part of the standard) */


	inline int ref_count();
	inline int ref_count_data();
	inline int ref_count_dim1();
	Array2D subarray(int i0, int i1, int j0, int j1);

};


template <class T>
Array2D<T>::Array2D() : data_(), v_(), m_(0), n_(0) {} 

template <class T>
Array2D<T>::Array2D(const Array2D<T> &A) : data_(A.data_), v_(A.v_), 
	m_(A.m_), n_(A.n_) {}




template <class T>
Array2D<T>::Array2D(int m, int n) : data_(m*n), v_(m), m_(m), n_(n)
{
	if (m>0 && n>0)
	{
		T* p = &(data_[0]);
		for (int i=0; i<m; i++)
		{
			v_[i] = p;
			p += n;
		}
	}
}



template <class T>
Array2D<T>::Array2D(int m, int n, const T &val) : data_(m*n), v_(m), 
													m_(m), n_(n) 
{
  if (m>0 && n>0)
  {
	data_ = val;
	T* p  = &(data_[0]);
	for (int i=0; i<m; i++)
	{
			v_[i] = p;
			p += n;
	}
  }
}

template <class T>
Array2D<T>::Array2D(int m, int n, T *a) : data_(m*n, a), v_(m), m_(m), n_(n)
{
  if (m>0 && n>0)
  {
	T* p = &(data_[0]);
	
	for (int i=0; i<m; i++)
	{
			v_[i] = p;
			p += n;
	}
  }
}


template <class T>
inline T* Array2D<T>::operator[](int i) 
{ 
#ifdef TNT_BOUNDS_CHECK
	assert(i >= 0);
	assert(i < m_);
#endif

return v_[i]; 

}


template <class T>
inline const T* Array2D<T>::operator[](int i) const
{ 
#ifdef TNT_BOUNDS_CHECK
	assert(i >= 0);
	assert(i < m_);
#endif

return v_[i]; 

}

template <class T>
Array2D<T> & Array2D<T>::operator=(const T &a)
{
	/* non-optimzied, but will work with subarrays in future verions */

	for (int i=0; i<m_; i++)
		for (int j=0; j<n_; j++)
		v_[i][j] = a;
	return *this;
}




template <class T>
Array2D<T> Array2D<T>::copy() const
{
	Array2D A(m_, n_);

	for (int i=0; i<m_; i++)
		for (int j=0; j<n_; j++)
			A[i][j] = v_[i][j];


	return A;
}


template <class T>
Array2D<T> & Array2D<T>::inject(const Array2D &A)
{
	if (A.m_ == m_ &&  A.n_ == n_)
	{
		for (int i=0; i<m_; i++)
			for (int j=0; j<n_; j++)
				v_[i][j] = A[i][j];
	}
	return *this;
}




template <class T>
Array2D<T> & Array2D<T>::ref(const Array2D<T> &A)
{
	if (this != &A)
	{
		v_ = A.v_;
		data_ = A.data_;
		m_ = A.m_;
		n_ = A.n_;
		
	}
	return *this;
}



template <class T>
Array2D<T> & Array2D<T>::operator=(const Array2D<T> &A)
{
	return ref(A);
}

template <class T>
inline int Array2D<T>::dim1() const { return m_; }

template <class T>
inline int Array2D<T>::dim2() const { return n_; }


template <class T>
Array2D<T>::~Array2D() {}




template <class T>
inline Array2D<T>::operator T**()
{
	return &(v_[0]);
}
template <class T>
inline Array2D<T>::operator const T**()
{
	return &(v_[0]);
}

/* ............... extended interface ............... */
/**
	Create a new view to a subarray defined by the boundaries
	[i0][i0] and [i1][j1].  The size of the subarray is
	(i1-i0) by (j1-j0).  If either of these lengths are zero
	or negative, the subarray view is null.

*/
template <class T>
Array2D<T> Array2D<T>::subarray(int i0, int i1, int j0, int j1) 
{
	Array2D<T> A;
	int m = i1-i0+1;
	int n = j1-j0+1;

	/* if either length is zero or negative, this is an invalide
		subarray. return a null view.
	*/
	if (m<1 || n<1)
		return A;

	A.data_ = data_;
	A.m_ = m;
	A.n_ = n;
	A.v_ = Array1D<T*>(m);
	T* p = &(data_[0]) + i0 *  n_ + j0;
	for (int i=0; i<m; i++)
	{
		A.v_[i] = p + i*n_;

	}	
	return A;
}

template <class T>
inline int Array2D<T>::ref_count()
{
	return ref_count_data();
}



template <class T>
inline int Array2D<T>::ref_count_data()
{
	return data_.ref_count();
}

template <class T>
inline int Array2D<T>::ref_count_dim1()
{
	return v_.ref_count();
}




} /* namespace TNT */

#endif
/* TNT_ARRAY2D_H */
It seems that declaration of object A is correct.

But why does not the constructor set m_ and n_?

Last edited on
Is this a template? Eigenvalue.getV(A);
No, this
Eigenvalue.getV(A);
is me trying to pass the array A into the getV() function in the Eigenvalue class.

If I remove that, it runs and displays the array A as expected in the console, so maybe I have some fundamental misunderstanding about how to pass the array into the function.
If I remove that, it runs and displays the array A as expected in the console, so maybe I have some fundamental misunderstanding about how to pass the array into the function.


If you remove it, does the error you've posted above go away? Just so we are on the same page, Array2D<T> is a template class, that acts like an array, but in and of itself is not an array. What does the getV function take as it's parameter?

Edit: After further inspection it looks like Array2D overloads the conversion operators, so just verify that the return value of the conversion operator matches the parameter for the function your are trying to call.
Last edited on
No, this Eigenvalue.getV(A); is me trying to pass the array A into the getV() function in the Eigenvalue class.
¿class?
1
2
Eigenvalue::getV(A); //class method (static)
Eigenvalue().getV(A); //using a (dummy) object to execute the method 


Yes, the error goes away if I remove that line.

getV() is a function of the Eigenvalue class, which I've put below. I'm sorry if I've omitted relevant code; the whole header file is too large to fit in a reply.

I have discovered that Eigenvalue class is a template class, which I do not know how to properly call functions from.

i.e. before the body of the class, this appears:

1
2
3
4
5
6
7
8
 namespace JAMA
{

//comments...

template <class Real>
class Eigenvalue
{ ... functions....




The function is here:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public:


   /** Check for symmetry, then construct the eigenvalue decomposition
   @param A    Square real (non-complex) matrix
   */

   Eigenvalue(const TNT::Array2D<Real> &A) {
      n = A.dim2();
      V = Array2D<Real>(n,n);
      d = Array1D<Real>(n);
      e = Array1D<Real>(n);

      issymmetric = 1;
      for (int j = 0; (j < n) && issymmetric; j++) {
         for (int i = 0; (i < n) && issymmetric; i++) {
            issymmetric = (A[i][j] == A[j][i]);
         }
      }

      if (issymmetric) {
         for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
               V[i][j] = A[i][j];
            }
         }
   
         // Tridiagonalize.
         tred2();
   
         // Diagonalize.
         tql2();

      } else {
         H = TNT::Array2D<Real>(n,n);
         ort = TNT::Array1D<Real>(n);
         
         for (int j = 0; j < n; j++) {
            for (int i = 0; i < n; i++) {
               H[i][j] = A[i][j];
            }
         }
   
         // Reduce to Hessenberg form.
         orthes();
   
         // Reduce Hessenberg to real Schur form.
         hqr2();
      }
   }


   /** Return the eigenvector matrix
   @return     V
   */
If this is a static method then...
Eigenvalue<double>::getV(A);
Last edited on
Using a dummy
Eigenvalue<double>().getV(A);

get me the following errors.

1
2
3
4
5
C:\Users\Wes\Desktop\TNT\TNT\main.cpp||In function 'int main()':|
C:\Users\Wes\Desktop\TNT\TNT\main.cpp|26|error: no matching function for call to 'JAMA::Eigenvalue<double>::Eigenvalue()'|
C:\Users\Wes\Desktop\headers\jama_eig.h|903|note: candidates are: JAMA::Eigenvalue<Real>::Eigenvalue(const TNT::Array2D<T>&) [with Real = double]|
C:\Users\Wes\Desktop\headers\jama_eig.h|73|note:                 JAMA::Eigenvalue<double>::Eigenvalue(const JAMA::Eigenvalue<double>&)|
||=== Build finished: 1 errors, 0 warnings ===|


However, when I try to use one of the suggestions, I still get an error:
C:\Users\Wes\Desktop\TNT\TNT\main.cpp|26|error: expected primary-expression before 'const'|



Trying it as a class (Eigenvalue<double>::getV(A);)gives me this error

1
2
3
C:\Users\Wes\Desktop\TNT\TNT\main.cpp||In function 'int main()':|
C:\Users\Wes\Desktop\TNT\TNT\main.cpp|26|error: cannot call member function 'void JAMA::Eigenvalue<Real>::getV(TNT::Array2D<T>&) [with Real = double]' without object|
||=== Build finished: 1 errors, 0 warnings ===|


I apologize for taking so much time on this, but I'd really like it to work, and I think once I get the hang of it it won't be so bad.
without object

That should tell you this is not a static function, which means, you need to create an object.

1
2
EigenValue<double> eigen = Eigenvalue<double>(A);
eigen.getV(A);


Or something along these lines...

Alternative...
Eigenvalue<double>(A).getV(A); //You have to decide..
Last edited on
¿why is it taking you so long to post the getV() prototype?

Eigenvalue<double>().getV(A); fails because you don't have that constructor. You have a constructor that ask for a matrix.
1
2
3
template <class Real>
class Eigenvalue{
  Eigenvalue(const TNT::Array2D<Real> &A);


So what you need to do
1
2
3
4
5
6
7
int main()
{
    Array2D< double > A(2,2, 1.0);    /* create MxN array; all ones */
    cout << A <<endl;
    Eigenvalue<double> meaningful_name(A);
    meaningful_name.getV(A);
}


As a note, I don't understand why would you need to repeat the matrix to operate with.
Edit: unless... it's an output argument.
Last edited on
I guess I was write when I said (likely simple) in the title. :-) It's working now, thank you.

Yes, it's the output argument. perhaps it's bad form to store it under the same name.

I know its worth it to do hardcore stuff in C++, but I miss being able to do something like Eigensystem[Matrix] in Mathematica and get it all done in one fell swoop. Thanks again for your help!
Topic archived. No new replies allowed.