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.
Related
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;
}
I am trying to make a generic selection sort function using templates.
What I have made is:
template<typename T>
void nrsort(T &a,int size)
{
// Applying Selection Sort
double temp; // This is the issue
for (int i = 0; i < size ; i++)
{
double minimum=a[i]; // This one too
for (int j = i+1; j < size ; j++)
{
if(a[j]<minimum)
{
temp=a[i];;
a[i]=a[j];
minimum=a[j];
a[j]=temp;
}
}
}
}
I want a generic template that may be able to sort integers, floating point numbers, characters, etc.
This above mentioned code works but the major problem is that I have hardcoded the double temp; and double minimum and conversion of data takes place everytime.
If I write my main method as follows:
int main()
{
int values[]={4,3,6,1};
nrsort(values,4);
for (int i = 0; i < 4 ; i++)
{
cout<<values[i]<<"\t";
}
return 0;
}
Then the type T deduced in the template is int [4] an array of four integers. Inside the function, all these are converted to double and the code works fine.
But my question is, Is there any way so that I don't have to hardcode it to double and use something like the generic type `T'.
Thanks.
Your function isn't as generic as it could be. The STL-way to solve such a problem is to use iterators. It will allow you to sort C-style arrays, std::vectors and anything else that provides a random access iterator. Your function should take a pair of iterators like this:
template <typename IteratorT>
void
my_sort(IteratorT begin, IteratorT end);
Then, if you #include <iterator>, you can query the value type (ie what you get if you dereference a IteratorT) like so
using ValueT = typename std::iterator_traits<IteratorT>::value_type;
Now, ValueT is a type alias for your type.
You can provide a convenience wrapper function if you like:
#include <utility> // for std::begin() and std::end()
template<typename ContainerT>
void
my_sort(ContainerT& container)
{
using std::begin;
using std::end;
my_sort(begin(container), end(container));
}
There is one problem: These function templates will match all too eagerly, even if the iterators are not random access iterators. You can use SFINAE trickery to enable your template only if std::iterator_traits<IteratorT>::iterator_category is std::random_access_iterator_tag. Or you could provide an overload that copies the elements (or pointers / iterators to them) into a std::vector, sorts that, and then copies the elements back. Sometimes, this is the best you can do.
If you fix the scope of temp, you can simply use auto:
template<typename T>
void nrsort(T &a,int size)
{
// Applying Selection Sort
for (int i = 0; i < size ; i++)
{
auto minimum=a[i]; // This one too
for (int j = i+1; j < size ; j++)
{
if(a[j]<minimum)
{
auto temp=a[i];;
a[i]=a[j];
minimum=a[j];
a[j]=temp;
}
}
}
}
It will automatically deduce the right type.
If I define a function which takes a double, I can generally call it with an int and get correct behavior.
double square(double d) {
return d * d;
}
square(1); // valid call
However, if I have a function that takes vector<double>, it is not valid to call it with vector<int>
double sum(const vector<double>& d) {
double s = 0;
for (int i = 0; i < d.size(); i++)
s += d[i];
return s;
}
vector<int> f(1,5);
sum(f); // Compiler error
One solution to this would be to use templates:
template<typename T>
double tsum(const vector<T>& d) {
double s = 0;
for (int i = 0; i < d.size(); i++)
s += d[i];
return s;
}
vector<int> f(1,5);
tsum<int>(f); // Valid
However, in this case, we have to specify the type as part of the function, which is a little clunky, especially if I want to define a dot product function which can do the dot products of arbitrary combinations of numeric types, such vector<int> and vector<double> and vector<float>, because now every time this function is called, the caller has to explicitly specify which vector is which particular numeric type.
Is there some way to define a function, either using traditional or new c++, such that calls like
sum(f) are valid and behave as expected?
You don't actually have to specify it (the compiler will "find it" through what's known as template argument deduction as #FredOverflow has mentioned in the comments):
#include <iostream>
#include <vector>
template<typename T>
T tsum(std::vector<T> const& d)
{
T s = 0;
for(auto x : d) { s += x; }
return s;
}
int main()
{
std::vector<int> f(1,5);
tsum(f);
std::vector<double> v(2, 6);
tsum(v);
return 0;
}
Live example
It should be noted that the standard library contains a function to do this already though: accumulate
I searched a lot on stackoverflow and google but nothing as my case. I want to declare a 2d array of my class box. It works normal, then i need a print function for it. If i printed the array inside main(), it was fine but now with a printer function i seem to get a lot of errors. Please help me with my mistake.
#include <iostream>
class box
{
private:
char life;
public:
box();
void display();
void input_alive();
void input_dead();
};
box::box()
{
life = '0';
}
void box::display()
{
std::cout << " " <<life <<" ";
}
void box::input_alive()
{
life = '1';
}
void box::input_dead()
{
life = '0';
}
void printer(box *array, int yy, int xx)
{
int i, j;
for(i=0; i<yy; i++) //PRINTER
{
for(j=0; j<xx; j++)
{
array[i][j].display();
if (j+1 == xx) //just newline for separate rows
std::cout << std::endl;
}
}
}
int main()
{
int row=5, col=5;
box arr[row][col];
arr[3][4].input_alive();
arr[1][1].input_alive();
printer(arr, row, col);
return 0;
}
this syntax of passing array by reference works fine in normal int/char arrays, but why not here. If i put printer function in main, it works fine :(. Do i have to use new or what? or how do i pass box array into function? thanks.
First of all, C++ doesn't support variable length arrays, so your code is not standards compliant and therefore is not portable.
Second, you can avoid all the pain by using std::array:
#include <array>
template <size_t ROWS, size_t COLS>
void printer(std::array<box, ROWS>, COLS>& arr)
{
for(int i=0; i<ROW; ++i)
{
for(int j=0; j<COL; ++j)
{
// do something with arr[i][j]
}
}
int main()
{
const int row=5;
const int col=5;
std::array<std::array<box, row>, col> arr;
arr[3][4].input_alive();
arr[1][1].input_alive();
printer(arr);
return 0;
}
Your solution is to forget about raw arrays. Instead, you use std::vector or std::array and write a Matrix class with operator(), as explained in the C++ FAQ. See also the next item in the FAQ for reasons why you'd want to prefer the (x, y) form to [x][y], but consider that there are good programmers who prefer the latter syntax (using a proxy class), so the case is perhaps not as clear as the FAQ says it is.
In any case, you need a Matrix class with a std::vector or std::array implementation. Raw arrays are the wrong tool for this task.
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;
}