I have a class which must be able to hold a type of float, double, long excetera. I would like to overload it in such a way that it can add two instances holding different types.
template <typename T>
class F{
public:
F(const T & t){a=t;}
T a;
F & operator+= (const F & rhs);
}
template<typename T>
F<T> F::operator+= (const F & rhs){
a+=rhs.a;
return *this
This is just pseudo code I've kept out irrelevant bits where I'm actually trying to use this sort of solution.
Now when trying to use:
F<int> first(5);
F<int> second(4);
first+=second; // Works
F<int> third(5);
F<float> fourth(6.2);
fourth+=third; // wont work
I can see why this doesn't work as it assumes the rhs argument is the same type as the lhs. I can also see there are potential problems in performing an operation which is int += long as if the long is big the type would need changing.
What I can't seem to find is a nice way to solve the problem. I would appreciate your inputs. Thanks
You need to make operator+= a template as well:
template <typename T>
class F{
public:
F(const T & t){ a = t; }
T a;
template<typename T2>
F& operator+=(const F<T2>& rhs);
}; // semicolon was missing
template<typename T>
template<typename T2>
F<T>& F<T>::operator+=(const F<T2>& rhs) {
a += rhs.a;
return *this; // semicolon was missing
} // brace was missing
Then you can do
F<int> a(4);
F<float> b(28.4);
b += a;
cout << b.a << endl; // prints 32.4
Here is a working example.
template <typename T>
class F{
public:
F(const T & t){a=t;}
T a;
template<typename T2>
F & operator+= (const F<T2> & rhs);
};
template<typename T>
template<typename T2>
F<T>& F<T>::operator+= (const F<T2> & rhs){
a+=(T)rhs.a;
return *this
}
EDIT:
fixed error, see comments
You can templatize operator+=:
template<typename G> F<T> & operator+= (const F<G> & rhs);
...assuming you can somehow convert a G to a T.
Related
Trying to implement operator overloading using the following code:
class Number
{
T value;
public:
Number(T v);
Number();
Number<T> operator+ (Number<T>&, const Number<T> &);
T getValue() { return value; };
};
template <typename T>
Number<T>::Number(T val):value(val) { }
template <typename T>
Number<T> Number<T>::operator+ (Number<T>& lhs, const Number<T> & rhs) {
return lhs.value + rhs.value;
}
Trying to emulate similar examples found online, but this attempt generates several compiler errors
'{' missing function header (old-style format list?)
binary 'operator +' has too many parameters
class template "Number" has no member "operator+"
Number<T> Number<T>::operator+ (Number<T>& lhs, const Number<T> & rhs)
With all the decisions: whether or not to include "<T>"; whether or not to use references for sends and returns; whether or not to use "const" and/or "friend"; and whether or not to use "this", "new" and/or "->"; it's confusing enough to search for outside help :).
Any idea what (many things) I'm doing wrong?
Thanks for your consideration
You're forgetting about the implicit this parameter that are present as the first parameter in a non-static member function.
To solve your probelm just remove the extra first parameter from operator+ as shown below:
template<typename T>
class Number
{
T value;
public:
Number(T v);
Number();
Number<T> operator+ (const Number<T> &);//REMOVED UNNECESSARY PARAMETER
T getValue() { return value; };
};
template <typename T>
Number<T>::Number(T val):value(val) { }
template <typename T>
Number<T> Number<T>::operator+ (const Number<T> & rhs) { //REMOVED UNNECESSARY PARAMETER
return value + rhs.value;//CHANGED lhs.value to value
}
The output of the program can be seen here.
Remove this line:
Number<T> operator+ (Number<T>&, const Number<T> &);
and define operator+ out of the class body this way:
template<typename T>
Number<T> operator+(Number<T> const& lhs, Number<T> const& rhs) {
auto ret{ lhs };
ret.value += rhs.value;
return ret;
}
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.
How can I make it so that (with objects of different template types) A*B and B*A give the same result, where the type of the result is determined according to the usual C++ type promotion rules?
For example:
int main()
{
number<float> A(2.0f);
number<double> B(3.0);
A*B; // I want 6.0 (double)
B*A; // I want 6.0 (double)
return 0;
}
At the moment, I can only multiply objects of the same template type. For example, something like this:
template<typename T>
class number
{
public:
number(T v) : _value(v) {}
T get_value() const { return _value; }
number& operator*=(const number& rhs)
{
_value *= rhs.get_value();
return *this;
}
private:
T _value;
};
template<typename T>
inline number<T> operator*(number<T> lhs, const number<T>& rhs)
{
lhs *= rhs;
return lhs;
}
EDIT: Or, as in the answers, I can multiply objects of different template types, but always returning the same type as lhs. Is there any way to instead return an object whose type is determined by the standard type promotion rules?
EDIT 2: I would like to avoid C++11 features if possible.
You have to templatize e.g. the rhsparameters:
template<typename T>
class number
{
public:
number(T v) : _value(v) {}
T get_value() const { return _value; }
template<class E>
number& operator*=(const number<E>& rhs)
{
_value *= rhs.get_value();
return *this;
}
private:
T _value;
};
template<class T, class E, class RET = decltype(T()*E())>
number<RET> operator*(number<T>& lhs, const number<E>& rhs)
{
return lhs.get_value()*rhs.get_value();
}
You can use std::common_type<> to obtain the type required for the return. For example
template<typename X>
struct number
{
// ...
template<typename Y>
number(number<Y> const&other); // needed in line 1 below
template<typename Y>
number&operator=(number<Y> const&other); // you may also want this
template<typename Y>
number&operator*=(number<Y> const&other); // needed in line 2 below
template<typename Y>
number<typename std::common_type<X,Y>::type> operator*(number<Y> const&y) const
{
number<typename std::common_type<X,Y>::type> result=x; // 1
return result*=y; // 2
}
};
I left out the implementations of the templated constructor and operator*=.
Unfortunately, std::common_type is C++11, which you want to avoid for obscure reasons. If you only work with built-in types (double, float, int, etc), you can easily implement your own version of common_type. However, if you want to do sophisticated meta-template programming, it is strongly recommended to move on to C++11 – it's already 4 years old and mostly backwards compatible.
You need a templated overload for the operator*()
template<typename T>
class number {
public:
// ...
template<typename U>
number& operator*=(const number<U>& rhs) {
// ...
}
// ...
};
And the same for the binary operator
template<typename T,typename U>
inline number<T> operator*(number<T> lhs, const number<U>& rhs) {
lhs *= rhs;
return lhs;
}
In an attempt to write a wrapper type for another type T, I encountered a rather obnoxious problem: I would like to define some binary operators (such as +) that forward any operation on wrapper to the underlying type, but I need these operators accept any of the potential combinations that involve wrapper:
wrapper() + wrapper()
wrapper() + T()
T() + wrapper()
The naive approach involves writing all the potential overloads directly.
But I don't like writing duplicated code and wanted a bit more challenge, so I chose to implement it using a very generic template and restrict the potential types with an enable_if.
My attempt is shown at the bottom of the question (sorry, this is as minimal as I can think of). The problem is that it will run into an infinite recursion error:
To evaluate test() + test(), the compile looks at all potential overloads.
The operator defined here is in fact a potential overload, so it tries to construct the return type.
The return type has an enable_if clause, which is supposed to prevent it from being a valid overload, but the compiler just ignores that and tries to compute the decltype first, which requires ...
... an instantiation of operator+(test, test).
And we're back where we started. GCC is nice enough to spit an error; Clang just segfaults.
What would be a good, clean solution for this? (Keep in mind that there are also other operators that need to follow the same pattern.)
template<class T>
struct wrapper { T t; };
// Checks if the type is instantiated from the wrapper
template<class> struct is_wrapper : false_type {};
template<class T> struct is_wrapper<wrapper<T> > : true_type {};
// Returns the underlying object
template<class T> const T& base(const T& t) { return t; }
template<class T> const T& base(const wrapper<T>& w) { return w.t; }
// Operator
template<class W, class X>
typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value,
decltype(base(declval<W>()) + base(declval<X>()))
>::type operator+(const W& i, const X& j);
// Test case
struct test {};
int main() {
test() + test();
return 0;
}
Here's rather clunky solution that I would rather not use unless I have to:
// Force the evaluation to occur as a 2-step process
template<class W, class X, class = void>
struct plus_ret;
template<class W, class X>
struct plus_ret<W, X, typename enable_if<
is_wrapper<W>::value || is_wrapper<X>::value>::type> {
typedef decltype(base(declval<W>()) + base(declval<X>())) type;
};
// Operator
template<class W, class X>
typename plus_ret<W, X>::type operator+(const W& i, const X& j);
As an addition to the comment of TemplateRex, I would suggest use a macro to implement all overloads and take the operator as an argument:
template<class T>
struct wrapper { T t; };
#define BINARY_OPERATOR(op) \
template<class T> \
T operator op (wrapper<T> const& lhs, wrapper<T> const& rhs); \
template<class T> \
T operator op (wrapper<T> const& lhs, T const& rhs); \
template<class T> \
T operator op (T const& lhs, wrapper<T> const& rhs);
BINARY_OPERATOR(+)
BINARY_OPERATOR(-)
#undef BINARY_OPERATOR
// Test case
struct test {};
test operator+(test const&, test const&);
test operator-(test const&, test const&);
int main() {
test() + test();
wrapper<test>() + test();
test() - wrapper<test>();
return 0;
}
This is something that is touched upon on the boost page for enable_if, in an unerringly similar situation (though the error they wish to avoid is different). The solution of boost was to create a lazy_enable_if class.
The problem, as it is, is that the compiler will attempt to instantiate all the types present in the function signature, and thus the decltype(...) expression too. There is also no guarantee that the condition is computed before the type.
Unfortunately I could not come up with a solution to this issue; my latest attempt can be seen here and still triggers the maximum instantiation depth issue.
The most straightforward way to write mixed-mode arithmetic is to follow Scott Meyers's Item 24 in Effective C++
template<class T>
class wrapper1
{
public:
wrapper1(T const& t): t_(t) {} // yes, no explicit here
friend wrapper1 operator+(wrapper1 const& lhs, wrapper1 const& rhs)
{
return wrapper1{ lhs.t_ + rhs.t_ };
}
std::ostream& print(std::ostream& os) const
{
return os << t_;
}
private:
T t_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, wrapper1<T> const& rhs)
{
return rhs.print(os);
}
Note that you would still need to write operator+= in order to provide a consistent interface ("do as the ints do"). If you also want to avoid that boilerplate, take a look at Boost.Operators
template<class T>
class wrapper2
:
boost::addable< wrapper2<T> >
{
public:
wrapper2(T const& t): t_(t) {}
// operator+ provided by boost::addable
wrapper2& operator+=(wrapper2 const& rhs)
{
t_ += rhs.t_;
return *this;
}
std::ostream& print(std::ostream& os) const
{
return os << t_;
}
private:
T t_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, wrapper2<T> const& rhs)
{
return rhs.print(os);
}
In either case, you can then write
int main()
{
wrapper1<int> v{1};
wrapper1<int> w{2};
std::cout << (v + w) << "\n";
std::cout << (1 + w) << "\n";
std::cout << (v + 2) << "\n";
wrapper2<int> x{1};
wrapper2<int> y{2};
std::cout << (x + y) << "\n";
std::cout << (1 + y) << "\n";
std::cout << (x + 2) << "\n";
}
which will print 3 in all cases. Live example. The Boost approach is very general, e.g. you can derive from boost::arithmetic to also provide operator* from your definition of operator*=.
NOTE: this code relies on implicit conversions of T to wrapper<T>. But to quote Scott Meyers:
Classes supporting implicit type conversions are generally a bad idea.
Of course, there are exceptions to this rule, and one of the most
common is when creating numerical types.
I have a better answer for your purpose: don't make it to complicated, don't use to much meta programming. Instead use simple function to unwrap and use normal expressions. You don't need to use enable_if to remove to operators from function overload set. If they are not used the will never need to compile and if the are used they give a meaningfull error.
namespace w {
template<class T>
struct wrapper { T t; };
template<class T>
T const& unwrap(T const& t) {
return t;
}
template<class T>
T const& unwrap(wrapper<T> const& w) {
return w.t;
}
template<class T1,class T2>
auto operator +(T1 const& t1, T2 const& t2) -> decltype(unwrap(t1)+unwrap(t2)) {
return unwrap(t1)+unwrap(t2);
}
template<class T1,class T2>
auto operator -(T1 const& t1, T2 const& t2) -> decltype(unwrap(t1)-unwrap(t2)) {
return unwrap(t1)-unwrap(t2);
}
template<class T1,class T2>
auto operator *(T1 const& t1, T2 const& t2) -> decltype(unwrap(t1)*unwrap(t2)) {
return unwrap(t1)*unwrap(t2);
}
}
// Test case
struct test {};
test operator+(test const&, test const&);
test operator-(test const&, test const&);
int main() {
test() + test();
w::wrapper<test>() + w::wrapper<test>();
w::wrapper<test>() + test();
test() - w::wrapper<test>();
return 0;
}
Edit:
As an intersting additional information I have to say, the orignal soultion from fzlogic compiles under msvc 11 (but not 10). Now my solution (presented here) doesn't compile on both (gives C1045). If you need to address these isues with msvc and gcc (I don't have clang here) you have to move logic to different namespaces and functions to prevent the compiler to uses ADL and take the templated operator+ into consideration.
template <class T>
class A
{
private:
T m_var;
public:
operator T () const { return m_var; }
........
}
template<class T, class U, class V>
const A<T> operator+ (const U& r_var1, const V& r_var2)
{ return A<T> ( (T)r_var1 + (T)r_var2 ); }
The idea is to overload the + operator once (instead of three) for the cases:
number + A, A + number, A + A (where number is of type T, the same as m_var).
An interesting case would be if m_var is e.g. int and r_var is long.
Any helps would be highly appreciated. Thank you.
The common pattern to achieve what you want is to actually perform it in the opposite direction: provide an implicit conversion from T to the template and only define the operator for the template.
template <typename T>
struct test {
T m_var;
test( T const & t ) : m_var(t) {} // implicit conversion
test& operator+=( T const & rhs ) {
m_var += rhs.m_var;
}
friend test operator+( test lhs, test const & rhs ) { // *
return lhs += rhs;
}
};
// * friend only to allow us to define it inside the class declaration
A couple of details on the idiom: operator+ is declared as friend only to allow us to define a free function inside the class curly braces. This has some advantages when it comes to lookup for the compiler, as it will only consider that operator if either one of the arguments is already a test.
Since the constructor is implicit, a call test<int> a(0); test<int> b = a + 5; will be converted into the equivalent of test<int> b( a + test<int>(5) ); Conversely if you switch to 5 + a.
The operator+ is implemented in terms of operator+=, in a one-liner by taking the first argument by value. If the operator was any more complex this would have the advantage of providing both operators with a single implementation.
The issue with your operator+ is you have 3 template parameters, one for the return type as well as the cast, but there is no way for the compiler to automatically resolve that parameter.
You are also committing a few evils there with casts.
You can take advantage of the that if you define operator+ as a free template function in your namespace it will only have effect for types defined in that namespace.
Within your namespace therefore I will define, using just T and U
template< typename T >
T operator+( const T & t1, const T& t2 )
{
T t( t1 );
t += t2; // defined within T in your namespace
return t;
}
template< typename T, typename U >
T operator+( const T& t, const U& u )
{
return t + T(u);
}
template< typename T, typename U >
T operator+( const U& u, const T& t )
{
return T(u) + t;
}
a + b in general is not covered by this template unless one of the types of a and b is in the namespace where the template was defined.
You should not overload op+ for unrelated types that you know nothing about – this can break perfectly working code that already exists. You should involve your class as at least one of the parameters to the op+ overload.
If you don't want an implicit conversion from T to A<T>, then I would just write out the overloads. This is the clearest code, and isn't long at all, if you follow the "# to #=" overloading pattern:
template<class T>
struct A {
explicit A(T);
A& operator+=(A const &other) {
m_var += other.m_var;
// This could be much longer, but however long it is doesn't change
// the length of the below overloads.
return *this;
}
A& operator+=(T const &other) {
*this += A(other);
return *this;
}
friend A operator+(A a, A const &b) {
a += b;
return a;
}
friend A operator+(A a, T const &b) {
a += A(b);
return a;
}
friend A operator+(T const &a, A b) {
b += A(a);
return b;
}
private:
T m_var;
};
C++0x solution
template <class T>
class A
{
private:
T m_var;
public:
operator T () const { return m_var; }
A(T x): m_var(x){}
};
template<class T,class U, class V>
auto operator+ (const U& r_var1, const V& r_var2) -> decltype(r_var1+r_var2)
{
return (r_var1 + r_var2 );
}
int main(){
A<int> a(5);
a = a+10;
a = 10 + a;
}
Unfortunately changing template<class T,class U, class V> to template<class U, class V> invokes segmentation fault on gcc 4.5.1. I have no idea why?