in an attempt to understand templates better (and thus be able to read basic documentation on c++), I am trying to perform basic operations on arrays as templates. Below is code that defines a function template for averaging an array:
#include <iostream>
#include <array>
using namespace std;
template<class T>
double GetAverage(T tArray[])
{
T tSum = T(); // tSum = 0
int n=tArray.size();
for (int nIndex = 0; nIndex < n; ++nIndex)
{
tSum += tArray[nIndex];
}
// Whatever type of T is, convert to double
return double(tSum) / n;
}
int main ()
{
array<int,5> data={0,1,2,3,4};
cout << GetAverage(data);
cin.get();
return 0;
}
For some reason, as you will see, the compiler runs into issues when dealing with properties of the array, such as array.size(), all within the defining code of a function. I get the following error:
error: no matching function for call to 'GetAverage'
cout << GetAverage(data);
^~~~~~~~~~
note: candidate template ignored: could not match 'T *' against 'array<int, 5>'
double GetAverage(T tArray[])
^
How can I refer to the properties of an object when defining a function which takes in said object as input (all the while using the language of templates)?
C++11 array is a STL container, not a C array thus the following is incorrect:
T tArray[]
A correct version of the above could be
#include <iostream>
#include <array>
#include <numeric>
using namespace std;
template<class T>
double GetAverage(T tArray)
{
// More compact version as suggested by juanchopanza
auto avg = std::accumulate(begin(tArray), end(tArray), 0.0)/tArray.size();
return avg;
}
int main ()
{
array<int,5> data={0,1,2,3,4};
cout << GetAverage(data);
cin.get();
return 0;
}
http://ideone.com/RyPqOr
if you intend to use something more sophisticated you might have to use a struct or a class since functions don't have partial specialization.
Related
The official documentation of boost library in C++ confirms that -1!! is defined. However, when I try to compute the double factorial of -1, it throws the following error
"Error in function boost::math::tgamma result of gamma is too large to represent". I can implement a code based on iteration to compute the same (if it comes to that), but would like to use optimized libraries wherever possible. Any suggestions on rectifying this issue?
#include <iostream>
#include <boost/math/special_functions/factorials.hpp>
int main(int argc, char const *argv[]) {
double t = boost::math::double_factorial<double>(-1);
std::cout << t <<"\n";
return 0;
}
This is the minimal working example.
This is how boost::math::double_factorial is declared:
namespace boost{ namespace math{
template <class T>
T double_factorial(unsigned i);
template <class T, class Policy>
T double_factorial(unsigned i, const Policy&);
}} // namespaces
According to the documentation for boost::math::double_factorial
The argument to double_factorial is type unsigned even though
technically -1!! is defined.
This means that, although mathematically -1!! is well defined, the function does not support negative inputs.
In fact, -1 will be silently converted to an unsigned, which will result in a large number-- hence the overflow.
As a workaround, you could declare an additional double_factorial function inside the namespace boost::math
Example, where for simplicity I have allowed for just -1!!.
#include <iostream>
#include <exception>
#include <boost/math/special_functions/factorials.hpp>
namespace boost { namespace math {
template <class T>
T double_factorial(int i) { if (i == -1) return T{1}; else throw(std::runtime_error("Unknown double factorial")); }
} }
int main(int argc, char const *argv[]) {
double t = boost::math::double_factorial<double>(-1);
std::cout << t <<"\n";
return 0;
}
See it live on Coliru
Warning
This solution will work, because the compiler will choose your new overload, inside the same namespace, when you call double_factorial with a negative argument.
It is however potentially dangerous: if a future version of boost allows for negative values, the code may not compile anymore, or ignore the new boost version.
A better solution is to wrap around double_gamma to a function you define, like as follows
template <class T>
T my_double_factorial(int i) {
if (i > 0)
return boost::math::double_factorial<T>(i);
else if (i == -1)
return T{1};
else
throw(std::runtime_error("Unknown double factorial"));
}
The function is declared as
template <class T>
T double_factorial(unsigned i);
and unsigned(-1) is a very large number.
I am working on my own library and I want to create function max(). I know that function like this exists in C++ and it isn't in namespace std, so erasing using namespace std; won't help. I am creating this function in my namespace like this:
namespace ml
{
template<typename T>T max(T cntr, int size)//I'm getting errors here
{
sort(cntr,0,size-1);//my function which just sorts elements, it's working fine
return cntr[size-1];
}
}
Here is my main function:
#include <iostream>
#include <ctime>
#include "mylib.hpp"
int main()
{
srand(time(NULL));
int* arr, n;
std::cin>>n;
arr = new int [n];
for(int i = 0; i < n; i++)
{
arr[i] = rand()%100;
}
int maximum = ml::max(arr,n);//I'm getting errors here
std::cout<<maximum<<'\n';
return 0;
}
Sorry for grammatical mistakes if i've done so.
If the purpose of the function is to search a C-style array, the signature should be template <typename T> T max(T* cntr, int size). (note the T* as the type of cntr) That way, when it's called with an int*, T is deduced as int, and that's the correct return type.
I am trying to learn how to use TBB, so I'm modifying a sample program I found that is designed to compute powers of an array of complex numbers. Originally, it was passing an array into the parallel_for loop, but I am trying to change it so that it passes in a vector. However, I cannot get my code to compile; I get the following error (compiled using g++ -g program_name.cpp -ltbb):
error: passing ‘const std::complex<double>’ as ‘this’ argument
discards qualifiers [-fpermissive] result[i] = z;
My code is below:
#include <cstdlib>
#include <cmath>
#include <complex>
#include <ctime>
#include <iostream>
#include <iomanip>
#include "tbb/tbb.h"
#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include "tbb/parallel_for_each.h"
#include "tbb/task_scheduler_init.h"
using namespace std;
using namespace tbb;
typedef complex<double> dcmplx;
dcmplx random_dcmplx ( void )
{
double e = 2*M_PI*((double) rand())/RAND_MAX;
dcmplx c(cos(e),sin(e));
return c;
}
class ComputePowers
{
vector<dcmplx> c; // numbers on input
int d; // degree
vector<dcmplx> result; // output
public:
ComputePowers(vector<dcmplx> x, int deg, vector<dcmplx> y): c(x), d(deg), result(y) { }
void operator() ( const blocked_range<size_t>& r ) const
{
for(int i=r.begin(); i!=r.end(); ++i)
{
dcmplx z(1.0,0.0);
for(int j=0; j < d; j++) {
z = z*c[i];
};
result[i] = z;
}
}
};
int main ( int argc, char *argv[] )
{
int deg = 100;
int dim = 10;
vector<dcmplx> r;
for(int i=0; i<dim; i++)
r.push_back(random_dcmplx());
vector<dcmplx> s(dim);
task_scheduler_init init(task_scheduler_init::automatic);
parallel_for(blocked_range<size_t>(0,dim),
ComputePowers(r,deg,s));
for(int i=0; i<dim; i++)
cout << scientific << setprecision(4)
<< "x[" << i << "] = ( " << s[i].real()
<< " , " << s[i].imag() << ")\n";
return 0;
}
You're trying to modify non-mutable member field result in const-qualified operator().
Resolve this discrepancy.
Edit #1: I have already mentioned the two keywords above. Either:
Remove const qualifier from operator():
void operator() ( const blocked_range<size_t>& r ) { ... }
Make result mutable:
mutable vector<dcmplx> result;
Additional erorrs may emerge after applying (although strongly preferred) variant no. 1. No. 2 is just for completeness and is used only in marginal situations.
It indeed results in an error with the 1st variant. This is because tbb::parallel_for takes Func by const&, so it can call only const-qualified member functions on your functor. Why? TBB doesn't want to waste performance by copying large functors (STL passes them by value).
I don't know what's the common practice here, I've never used this library.
Edit #2: Probably all you were missing was that result wasn't a reference:
vector<dcmplx> &result;
Now you'll be able to modify it, even in const-qualified operator(). Modifying a member that gets destructed afterwards wouldn't make sense.
Don't forget to change the constructor's signature to pass y by reference, too.
Off topic issues in your code:
Not included <vector> header
using namespace bulky_namespace globally
not using size_t for i in the for-loop
maybe more...
Here is my Matrix.cpp file. (there's a separate Matrix.h file)
#include <iostream>
#include <stdexcept>
#include "Matrix.h"
using namespace std;
Matrix::Matrix<T>(int r, int c, T fill = 1)
{
if (r > maxLength || c > maxLength) {
cerr << "Number of rows and columns should not exceed " << maxLen << endl;
throw 1;
}
if (r < 0 || c < 0) {
cerr << "The values for the number of rows and columns should be positive" << endl;
throw 2;
}
rows = r;
cols = c;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
mat[i][j] = fill;
}
This gives the following
error: invalid use of template-name ‘Matrix’ without an argument list
What's the problem in my code?
EDIT: The class Matrix is defined with a template<class T>
EDIT:
Here's my Matrix.h file:
#include <iostream>
#include <math.h>
#define maxLength 10;
using namespace std;
template <class T>
class Matrix
{
public:
Matrix(int r, int c, T fill = 1);
private:
int rows, cols;
T mat[10][10];
};
And here's the Matrix.cpp file:
#include <iostream>
#include <stdexcept>
#include "Matrix.h"
using namespace std;
template<class T>
Matrix<T>::Matrix(int r, int c, T fill = 1)
{
}
This gives the following error:
Matrix.cpp:12:43: error: default argument given for parameter 3 of
‘Matrix::Matrix(int, int, T)’ Matrix.h:16:3: error: after previous
specification in ‘Matrix::Matrix(int, int, T)’
What is wrong in my code?
If your class is template then correct definition should be,
template<class T>
Matrix<T>::Matrix(int r, int c, T fill) // don't give default argument
...
Also, don't forget to include this Cpp file where you use this class. Because in the case of templates, full body should be visible to all translation units.
Edit: After your edited question, I noticed that the error says it all.
You are not suppose to give the default argument inside the definition of the method. It's adequate to give in the declaration(which you already gave). Make your template definition as shown above and the error shall disappear.
You should write as:
template<class T>
Matrix<T>::Matrix(int r, int c, T fill = 1)
{
..
}
Yes, it's tedious. And it might not be a good idea to put
the template definitions in the source file, refer to
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
So the easiest way is to put the definitions of the template members
inside the class template definition in header file.
Below is a simple program in c++0x that makes use of packaged_task and futures. while compiling the program i get error : variable 'std::packaged_task pt1' has initializer but incomplete type
the program is below
#include <future>
#include <iostream>
using namespace std;
int printFn()
{
for(int i = 0; i < 100; i++)
{
cout << "thread " << i << endl;
}
return 1;
}
int main()
{
packaged_task<int> pt1(&printFn);
future<int> fut = pt1.get_future();
thread t(move(pt1));
t.detach();
int value = fut.get();
return 0;
}
The class template packaged_task is undefined for the general case. Only a partial specialization for function type parameters is defined. See the current draft:
template<class> class packaged_task; // undefined
template<class R, class... ArgsTypes>
class packaged_task<R(ArgTypes...)> {
...
void operator()(ArgTypes...);
...
};
Since your printFn function doesn't take any parameters and returns an int you need to use the packaged_task<int()> type.