1. check your calc_balance(), get_balance() methods, if they return double that defeats the whole purpose of having templates in the first place; they should return T, not double to be true templates
2. templates - header - implementation combo is a rich area of fun, I'll leave you to decide how you want to do it as that is not the main focus of this thread (
http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file)
3. let's focus on the main topic here: friend operator << - what you're trying to do is a bound template friend operator << to template class tester so that each specialization of tester gets a matching specialization of the friend operator. To get there you have to:
(a) forward declare tester;
(b) forward declare the friend operator;//if this did not take a tester argument (a) would not be necessary;
(c) now declare (and in your case also define since several of the methods are inline) the actual template class tester where the friend function is declared with a blank <> or with <T> which tells the compiler that operator << can only access tester<T> for the same T as is instantiating class tester (you can leave <> blank as the compiler already sees T at the class template declaration level)
4. Implement the operator
5. It is redundant to have print(), print_elements() and operator<< overload for the same class; I have removed the first two and everthing is handled by the insertion operator overload
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
|
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
using namespace std;
template <typename T> class tester;
template <class T>
ostream & operator<< (std::ostream & os, const tester<T> & tst);
template <typename T>
class tester {
private:
const vector<T> vd;
mutable unique_ptr<T> balance;
inline T calc_balance() const {
return accumulate(vd.begin(), vd.end(), 0.0);
}
// print results are cached, hence mutable
mutable string generated_stream{};
mutable bool stream_generated {false};
public:
explicit tester<T>(const vector<T> & test_balance) : vd{ test_balance }, balance(nullptr) { }
~tester<T>() {}
inline T get_balance() const {
if (!balance) balance = std::make_unique<T>(calc_balance());
return *balance;
}
inline T get_avg() const {
// if (!balance) balance = get_balance();
return (calc_balance()) / vd.size();
}
friend std::ostream & operator<< <>(std::ostream & os, const tester<T> & tst);
};
int main()
{
std::vector<double> v{12.2, 13.3, 99.3, 100.3, 101.33, -99};
tester<double> b(v);
cout<<b<<"\n";
}
template <class T>
std::ostream & operator<< (std::ostream & os, const tester<T> & tst)
{
os<<"Balance entries are: \n";
for(auto& elem : tst.vd)
{
os<<elem<<"\t";
}
os<<"\nBalance : " << tst.get_balance() << " \tAvg : " << tst.get_avg() <<"\n";
return os;
}
|
Output1 2 3 4 5 6 7
|
Balance entries are:
12.2 13.3 99.3 100.3 101.33 -99
Balance : 227.43 Avg : 37.905
Process returned 0 (0x0) execution time : 0.031 s
Press any key to continue.
|
edit: within class declaration/definition not necessary to typename <T> the ctor/dtor