This Vec template supports several functions such as multiplying a vector by scalar and adding vector to another vector.
The thing that is confusing me is that why the overloading of the second operator* is outside of the class template?
The operator* which is declared in the class overloads vectorXscalar
The one declared outside supports scalarXvector
template <class T>
class Vec {
public:
typename list<T>::const_iterator begin() const {
return vals_.begin();
}
typename list<T>::const_iterator end() const {
return vals_.end();
}
Vec() {};
Vec(const T& el);
void push_back(T el);
unsigned int size() const;
Vec operator+(const Vec& rhs) const;
Vec operator*(const T& rhs) const; //here
T& operator[](unsigned int ind);
const T& operator[](unsigned int ind) const;
Vec operator,(const Vec& rhs) const;
Vec operator[](const Vec<unsigned int>& ind) const;
template <class Compare>
void sort(Compare comp) {
vals_.sort(comp);
}
protected:
list<T> vals_;
};
template <class T>
Vec<T> operator*(const T& lhs, const Vec<T>& rhs); //and here!
template <class T>
ostream& operator<<(ostream& ro, const Vec<T>& v);
The operator* declared inside the template class could equally be written outside the class as
template <class T>
Vec<T> operator*(const Vec<T>& lhs, const T& rhs);
It can be written inside the class with a single argument (representing the rhs) because there is the implied *this argument used as the lhs of the operator.
The difference with the operator* defined outside the class is that the lhs of the operator is a template type. This allows the arguments to be supplied either way around when using the operator.
You are allowed to define the operator outside of a class with any arbitrary lhs and rhs types, but within the class are restricted to only varying the rhs. The compiler would select the best match of any defined operator* given the argument types.
Related
I am attempting to create a class that takes a priority queue and reverses the priorities. I include a bool operator<() function as a member function of the class, but no matter how I structure this function, the operator never seems to be overloaded.
Here is my class:
template<typename T>
class MinPQ{
public:
bool empty() const {
return pq.empty();
}
unsigned int size() const {
return pq.size();
}
void push(const T& element){
pq.push(element);
}
const T& min() const {
return pq.top();
}
void remove_min(){
pq.pop();
}
bool operator<(const T& element) const {
return pq < element;
}
private:
priority_queue<T> pq;
};
EDIT
I also tried changing the overloading function to the following and do not undertsand why that isn't working either.
bool operator<(const T& element){
return this < element;
}
Your operator< is meaningless. The only thing it can do is comparing MinPQ<T> object with T object. If you want to compare two T objects you should do this:
1) If the template type T can take only a handful of types, you can write comparison operators explicitly for each of these types:
bool operator<(const T& lhs, const T& rhs)
{
return lhs > rhs;
}
note: each operator< should be a non-member function. Or a member function of class T with a single argument.
2) write a comparison functor:
template <class T> struct CompareT
{
bool operator()(const T& lhs, const T& rhs) const
{
return lhs > rhs;
}
};
and then declare pq member as follows:
priority_queue<T, std::vector<T>, CompareT<T>> mq;
3) If you want simply to inverse priorities, you could simply use std::greater class:
priority_queue<T, std::vector<T>, std::greater<T>> mq;
Suppose I have a small class template as below
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
private:
T data;
};
Now I add the following definitions declarations:
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
SillyClass<T> operator+ (const SillyClass& other);
SillyClass<T> operator+ (const T& val);
private:
T data;
};
and now (after I write the appropriate definitions) I can do things like
SillyClass<int> a(1);
SillyClass<int> b(a);
SillyClass<int> c = a + b;
SillyClass<int> d = a + 3;
So far, so good. However, to be able to write something like
SillyClass<int> e = 3 + a;
I found that must add the following declaration to my class
template<typename T2> friend SillyClass<T2> operator+
(const T2& val, const SillyClass<T2>& other);
so it now reads
template<typename T> class SillyClass {
public:
SillyClass(const T val);
SillyClass(const SillyClass& other);
SillyClass<T> operator+ (const SillyClass& other);
SillyClass<T> operator+ (const T& val);
template<typename TT> SillyClass<TT> friend operator+
(const TT& val, const SillyClass<TT>& other);
private:
T data;
};
I didn't find this in a book and I'd like some help to understand what's happening on this last declaration. For instance, with what is my class being befriended here? Why the additional template declaration? What alternatives do I have in terms of different declarations that lead to the same result (being able to perform 3+a, say)?
Thanks.
with what is my class being befriended here? Why the additional template declaration?
The following expression declared inside your class is a friend declaration:
template<typename TT> SillyClass<TT> friend operator+
(const TT& val, const SillyClass<TT>& other);
The above expression declares your class a friend with a family of overloaded operator+s that take as their left-hand-side parameter a type TT and as their right-hand-side an object SillyClass<TT>. Note though that this is a declaration and not a definition. That is, in order for this to work the template overloaded operator+, must be defined.
What alternatives do I have in terms of different declarations that
lead to the same result (being able to perform 3+a, say)?
For binary operators in order for them to be symmetric must be declared outside the class definition as free functions, and in order to have access to the private members of their class parameters you declare them as a friend function of the respective class.
Based on these lines I would go along with the following implementation:
template<typename T> class SillyClass {
T data;
public:
SillyClass(const T val) : data(val) {}
SillyClass(const SillyClass& other) : data(other.data) {}
template<typename T1, typename T2>
friend SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lsh, SillyClass<T2>& rhs);
template<typename T1, typename T2>
friend SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lsh, T2 const &rhs);
template<typename T1, typename T2>
friend SillyClass<typename std::common_type<T1, T2>::type>
operator+(T1 const &rhs, SillyClass<T2> const &rsh);
};
template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lhs, SillyClass<T2>& rhs) {
return SillyClass<typename std::common_type<T1, T2>::type>(lhs.data + rhs.data);
}
template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type>
operator+(SillyClass<T1> const &lhs, T2 const &rhs) {
return SillyClass<typename std::common_type<T1, T2>::type>(lhs.data + rhs);
}
template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type>
operator+(T1 const &lhs, SillyClass<T2> const &rhs) {
return SillyClass<typename std::common_type<T1, T2>::type>(rhs.data + lhs);
}
Live Demo
Instead of only declaring your operator in class, you can define the friend operator inside your class:
SillyClass<T> friend operator+(const T& val, const SillyClass<T>& other)
{
// define it here
}
This way, for each instance of your class, a corresponding friend will be generated. The whole thing works based on something called friend name injection.
Now back to your problem. If you just use an in-class declaration
friend operator+(const T& val, const SillyClass<T>& other);
and then outside your class you define
template<typename T>
friend operator+(const T& val, const SillyClass<T>& other)
you'll get a linker error. Why? Because suppose T=int when you instantiate the class. Then the declaration in your class will read as
friend operator+(const int& val, const SillyClass<int>& other);
and will be a better match than the above template definition whenever you invoke your operator+ on SillyClass<int> and some int. So the linker won't be able to find the definition of the required int instantiation, hence a linker error. On the other hand, the solution I proposed at the beginning of the answer guarantees a corresponding definition for every type, so it will work without any headaches.
I have a template class typically instantiated by <double>.
My header has something like:
template <typename T> class F;
// Non-member functions
template <typename T> const F<T> operator*(F<T> lhs, const F<T>& rhs);
template <typename T> const F<T> operator*(const F<T>& lhs, const T& rhs);
template <typename T>
class F
{
// blah blah
F<T>& operator*=(const F<T>& rhs);
F<T>& operator*=(const T& rhs_scalar);
// blah
friend const F<T> operator*(const F<T>& lhs, const T& rhs) { return F(lhs) *= rhs; }
friend const F<T> operator*(const T& lhs, const F<T>& rhs) { return F(rhs) *= lhs; }
};
In my .cpp file, I have something like:
#include "F.H"
// lots of template<typename T> returntype F<T>::function(args){ body }
template <typename T>
F<T>& F<T>::operator*=(const F<T>& rhs)
{
// check sizes, etc
// do multiplication
return *this;
}
template <typename T>
F<T>& F<T>::operator*=(const T& rhs_scalar)
{
for(auto &lhs : field_) // field_ is a vector holding values
{
lhs *= rhs_scalar;
}
return *this;
}
// Non-member parts
template <typename T> operator*(F<T> lhs, const F<T>& rhs)
{ lhs *= rhs; return lhs; }
template <typename T> operator*(const F<T>& lhs, const T& rhs)
{ return F<T>(lhs) *= rhs; }
template class F<double>;
template const F<double> operator*<double>(F<double>, const F<double>&);
This compiles and runs ok, and allows things like:
F<double> test(..);
test *= 2.5; test *= 10; test /= 2.5; test /= 10; // and so on
The question I have is: Can I reduce the number of declarations and definitions of my operators, whilst retaining the ability to implicitly promote an int to a double, etc? Can I rearrange the code so that the friend .. operator*(..) bodies are defined outside of the header file? (I suspect this would involve more specific instantiations in one or both of the header and the cpp file)
(Side note: how? Scott Meyer's Item 46 in 'Effective C++' describes implicit parameter conversion, but it seems like that describes allowing the construction of a temporary object to allow (in that case) Rational(int) * Rational_object_already_created;)
Can I reduce the number of declarations and definitions of my operators, whilst retaining the ability to implicitly promote an int to a double, etc?
You can do that by providing a converting constructor.
template <typename T2>
F(F<T2> const& f2 ) {...}
I have a template class for which I'm overloading operator+, but need it to potentially return a different data type than what the class is instantiated for. For example, the following snippet performs the standard mathematical definition of either vector*vector (inner product), vector*scalar, or scalar*vector. To be specific, let's say I have a Vector<int> and the scalar is of type double -- I want to return a double from the "vector*scalar" operator+ function.
I'm pretty sure I'm missing some template<class T> statements for the friend functions(?), but this snippet isn't meant to compile.
template<class T>
class Vector
{
private:
std::vector<T> base;
public:
friend Vector operator*(const Vector& lhs, const Vector& rhs); // inner product
Vector<T> operator*(const T scalar); // vector*scalar
friend Vector operator*(const T scalar, const Vector& rhs); // scalar*vector
};
template<class T>
Vector<T> operator*(const Vector<T>& lhs, const Vector<T>& rhs) // inner product
{
assert( lhs.base.size() == rhs.base.size() );
Vector result;
result.base.reserve(lhs.base.size());
std::transform( lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base), std::multiplies<T>() );
return result;
}
template<class T>
Vector<T> Vector<T>::operator*(const T scalar) // vector*scalar
{
Vector result;
result.base.reserve(base.size());
std::transform( base.begin(), base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );
return result;
}
template<class T>
Vector<T> operator*(const T scalar, const Vector<T>& rhs) // scalar*vector
{
Vector result;
result.base.reserve(rhs.base.size());
std::transform( rhs.base.begin(), rhs.base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );
return result;
}
I guess what you want is to return a Vector with the value type being the type returned by the per-component operation, which is not necessarily the type of the scalar.
For example:
Vector<int> * int -> Vector<int>
Vector<int> * double -> Vector<double>
Vector<double> * int -> Vector<double>
Vector<char> * float -> Vector<float>
etc.
For this, you should define the two input types separately, let's say T1 and T2 (and one or two of the operands is a Vector of it). You don't want to simply use the scalar type (for vector * scalar, or scalar * vector operation) as the result, otherwise it might be converted (see my 3rd example: The result would then be Vector<int>.
The above can be done using decltype to find the third (result) type.
For simplicity, define the operator as a non-member:
template<typename T1, typename T2, typename T3 = decltype(std::declval<T1>() * std::declval<T2>())>
Vector<T3> operator*(const Vector<T1>& lhs, const T2 & scalar) // inner product
{
Vector<T3> result;
//...
return result;
}
The interesting part is
T3 = decltype(std::declval<T1>() * std::declval<T2>())
Here, we find the type T3 using the other two types T1 and T2. First, we construct two values with unimportant value (the std::declval function is a helper function returning the type given as a template parameter). Then we multiply those values, but again the result is unimportant; we're only interested in the type. That's what the third part does: decltype gives you the type of the expression (without evaluating it).
The other operators can be implemented analogous.
In order to make those operators friends, you need the syntax
template<...> friend ...
as seen in Danvil's answer.
The friend declaration should look like this:
template<class S>
class Vector
{
private:
std::vector<S> base;
public:
template<class T> friend T operator*(const Vector<T>& lhs, const Vector<T>& rhs); // inner product
template<class T> friend Vector<T> operator*(const T scalar); // vector*scalar
template<class T> friend Vector<T> operator*(const T scalar, const Vector<T>& rhs); // scalar*vector
};
And the rest of the code like this:
template<class T>
T operator*(const Vector<T>& lhs, const Vector<T>& rhs) // inner product
{
assert( lhs.base.size() == rhs.base.size() );
Vector<T> result;
result.base.reserve(lhs.base.size());
std::transform( lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base), std::multiplies<T>() );
return result;
}
template<class T>
Vector<T> operator*(const Vector<T>& lhs, const T scalar) // vector*scalar
{
return scalar*lhs;
}
template<class T>
Vector<T> operator*(const T scalar, const Vector<T>& rhs) // scalar*vector
{
Vector<T> result;
result.base.reserve(rhs.base.size());
std::transform( rhs.base.begin(), rhs.base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );
return result;
}
You can add more template parameters as such:
template<class T, class S>
Vector<S> Vector<T>::operator*(const S scalar)
and make sure you use S for the scalar type and T for the vector element type in the correct places in the function body.
I create a template class and want to overload an operator + (several times). I do this in the following way
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
....
template <typename T>
class Polynomial {
....
public:
....
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
friend const Polynomial<T> operator + <> (const Polynomial<T>& poly, const T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
However, I got the following error (which corresponds to the line that begins with 'friend')
problem2.cpp:282:45: error: declaration of ‘operator+’ as non-function
problem2.cpp:282:45: error: expected ‘;’ at end of member declaration
problem2.cpp:282:47: error: expected unqualified-id before ‘<’ token
Following Raxvan's advise, I've changed the code
template class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other);
....
template <typename T>
class Polynomial {
....
public:
....
friend ostream& operator << <> (ostream& out, const Polynomial<T>& other);
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
template <typename NOT_T>
friend const Polynomial<NOT_T> operator +(const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other) {
// implementation
}
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
And in this code I don't have problems with operator << as I had with operator +. Can anyone explain the defference?
The problem is subtle. Your syntax is very close to being
correct. I think your friend declaration should be:
friend Polynominal<T> const operator+<T>( ... );
but both VC++ and g++ accept:
friend Polynominal<> const operator+<T>( ... );
when they can see the declaration:
template <typename T>
const Polynomial<T> operator+(const Polynomial<T>& poly, const T& scalar);
(I can't find anything in the standard to justify this off hand,
but since both VC++ and g++ do it, I suppose that it's something
I've missed.)
And therein lies the problems. The declaration at namespace
scope of operator+ is hidden by the in-class definition. The
compiler complains because the operator+ it finds (the in
class definition) isn't a template itself (although it is
a member of a class template).
If you don't have the problem with operator<<, it's because
you don't have a member function with the same name.
There are several ways of solving this problem. The simplest is
probably to make all of the operator+ friends. Or not: the
most common approach to this is to implement operator+ in
terms of operator+= (which should be a member, in all cases).
In which case, operator+ doesn't have to be a friend.
Or you don't make operator+ a template at all, but definite it
inside your class template:
template <typename T>
class Polynomial
{
friend Polynomial operator+( Polynomial const& lhs, Polynomial const& rhs )
{
// ...
}
friend Polynomial operator+( Polynomial const& lhs, T const& rhs )
{
// ...
}
friend Polynomial operator+( T const& lhs, Polynomial const& rhs )
{
// ...
}
}
(Note that the functions being defined are not templates, but
separate overloaded non-template functions, one for each
instantiation of Polynomial. But the results end up being the
same.)
In this case, you probably would want to have a member function,
called by the operator+ functions, which would do the actual
work; you don't want too much code directly inline like this.
Your operator+ is a function template, to make this a friend, you need to declare it fully including the template parameters, however with a different template parameter, for example:
#include <iostream>
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
Polynomial operator +(const Polynomial& other) const {
std::cout << "inline +" << std::endl;
}
// Here introduce a different type to indicate that this is a template...
template <typename U>
friend const Polynomial<U> operator + (const Polynomial<U>& poly, const U& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
std::cout << "friend +" << std::endl;
}
int main(void)
{
Polynomial<int> f;
f = f + 1;
f = f + 1.; // this fails
f = f + Polynomial<int>();
}
You have to have the same definition when you label a function as friend, this includes the template used above with another type , not T
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
template < class NOT_T> //must respect the deffinition from above
friend const Polynomial<NOT_T> operator + (const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar)
{
//...
}
Edit:
For a simplified explanation i have changed the function to foo and bar to illustrate the difference in declarations:
template <typename T> class Polynomial;
template <typename T>
void bar(const Polynomial<T>& );
void foo(const Polynomial<float> & );//foo for speciffic float
template <typename T>
class Polynomial {
public:
template <typename> //this is also valid declaration;
friend void bar(const Polynomial<T> & );
//it just has to have template because it's a template functions declaration
//not a valid declaration:
//friend void bar <> (const Polynomial<T> & );
//this declaration has no template;
//it refers to a foo function specific to Polynomial<T> type
//so if you use Polynomial<float> there must be a foo for floats
friend void foo(const Polynomial<T> &);
};
template <class T>
void bar(const Polynomial<T>&)
{
}
void foo(const Polynomial<float> &)
{
}
void main()
{
Polynomial<float> pf;
Polynomial<int> pi;
foo(pi);//error since there is not **foo** declared for int
foo(pf);//ok; we have **foo** for Polynomial<float>
bar(pf);
bar(pi);//both ok since bar is templated function;
}
Raxvan.