I've written a class Number that contains only one attribute: T value. I'm currently learning about templates, so T is the data type. What I want to achieve is doing the following sort of computation.
Number<int>(2) + Number<double>(1.2)
What I have so far can do a operation, but it fails when there are two different datatypes. So far I've written this:
//class template
template<class T>
class Number
{
public:
T value;
Number(T num1)
{
value = num1;
}
Number<T> operator + ( const Number<T> &other) const
{
return Number<decltype(value+other.value)> (value+other.value);
}
};
It only does the arithmic operation when the datatypes are the same:
Questions:
Why does the program only work with the same datatypes?
This can I answer for a part by myself. I use the line:
Number<T> operator + ( const Number<T> &other) const
So if the left handside is of type int. Every T becomes an int. I don't know how I need to change it without getting an error.
What do I need to fix in order to do computations with different
datatypes?
Edit:
A constraint is that the template may contain only one type argument
Besides declaring a friend operator+ with two template parameters as suggested, you can also place a secondary template for the member function operator+, which allows you to do casting plus.
template<typename T>
class Number
{
public:
T value;
Number(const T&num1)
{
value = num1;
}
template <typename X> auto operator + ( const Number<X> &other) const
{
auto c = this->value + other.value;
return Number<decltype(c)> ( c );
}
};
#include <iostream>
int main()
{
Number<int> n{2};
Number<double> a{3.4};
std::cout << (a+n).value << std::endl;
}
Or, you may use a friend function (I think that this is more symbolic consistent.)
template<typename T>
class Number
{
public:
T value;
Number(T num1)
{
value = num1;
}
Number& operator +=( const Number<T> &other)
{
this->value += other.value;
return *this;
}
};
template <typename T1,typename T2> auto operator+(const Number<T1>&a, const Number<T2>&b)
{
auto c = a.value + b.value;
return Number<decltype(c)>( c );
}
#include <iostream>
#include <type_traits>
template <typename T>
struct Number {
Number(T _value = T(0)) : value(_value) {}
template <typename S>
Number(const Number<S>& n) : value(n.value) {}
T value;
template <typename S>
friend Number<S> operator+(const Number<S>& a, const Number<S>& b);
};
template <typename S>
Number<S> operator+(const Number<S>& a, const Number<S>& b) {
return Number<S>{a.value + b.value};
}
int main() {
std::cout << operator+<typename std::common_type<int, double>::type>(Number<int>{1}, Number<double>{1.2}).value << std::endl;
return 0;
}
this is a c++11 implementation. operator+ contains exactly one argument. I hope this is what you want.
Related
I am very confused about how to get the template argument of the returned object in simple operator overloading.
This is my code:
#include <iostream>
template <typename T>
class numeric {
public:
numeric(): value_{0} {}
numeric(T value): value_{value} {}
numeric(const numeric& other) { value_ = other.value_; }
~numeric() {}
template <typename O>
numeric<T> operator+(const numeric<O>& other) {
return numeric<T>(value_ + other.value_);
}
friend std::ostream& operator<<
(std::ostream& os, const numeric& other) {
os << other.value_;
return os;
}
private:
T value_;
};
int main() {
numeric<int> x = 10;
numeric<float> y = 5.5;
std::cout << (x + y);
return 0;
}
And my desired result was to print out 15.5 on the console.
Even if your attempt didn't have a problem with accessing a private member of another class - which could be worked around by making the member public - you would have a problem with inconsistent behaviour where x + y results in 15 because the type of the result is numeric<int>. y + x would yield the desired 15.5.
You can fix both the access problem, and the return type by using friend operator overload template. Use a template type parameter for both operands. Return wrapper of common type. You'll need to define it outside the class template so that you don't get a different definition for each class template instance:
template <typename T>
class numeric {
...
template<class L, class R>
friend auto operator+(const numeric<L>&, const numeric<R>&);
...
};
template<class L, class R>
auto operator+(const numeric<L>& l, const numeric<R>& r) {
using common_type = numeric<std::common_type_t<L, R>>;
return common_type(l.value_ + r.value_);
}
Consider the following set of classes and the relationship of their operators: We can implement them in two distinct ways. The first where the operators are defined within the class, and the latter where they are defined outside of the class...
template<typename T>
struct A {
T value;
T& operator+(const A<T>& other) { return value + other.value; }
// other operators
};
temlate<typename T>
struct B {
T value;
T& operator+(const B<T>& other) { return value + other.value; }
};
// Or...
template<typename T>
struct A {
T value;
};
template<typename T>
T& operator+(const A<T>& lhs, const A<T>& rhs) { return lhs.value + rhs.value; }
// ... other operators
template<typename T>
struct B {
T value;
};
template<typename T>
T& operator+(const B<T>& lhs, const B<T>& rhs) { return lhs.value + rhs.value; }
// ... other operators
Is there any way in C++ where I would be able to make a single class or struct of operators to where I could simply be able to declare or define them within any arbitrary class C without having to write those same operators multiple times for each class? I'm assuming that the operators will have the same behavior and property for each distinct class that defines them considering that they will all follow the same pattern.
For example:
template<typename T, class Obj>
struct my_operators {
// define them here
};
// Then
template<typename T>
struct A {
T value;
my_operators ops;
};
template<typename T>
struct B {
T value;
my_operators ops;
};
Remember I'm restricting this to C++17 as I'm not able to use any C++20 features such as Concepts... If this is possible, what kind of method or construct would I be able to use, what would its structure and proper syntax look like? If this is possible then I'd be able to write the operators once and just reuse them as long as the pattern of the using classes matches without having to write those operators for each and every individual class...
What about using CRTP inheritance?
#include <iostream>
template <typename T>
struct base_op
{
auto operator+ (T const & o) const
{ return static_cast<T&>(*this).value + o.value; }
};
template<typename T>
struct A : public base_op<A<T>>
{ T value; };
template<typename T>
struct B : public base_op<B<T>>
{ T value; };
int main()
{
A<int> a1, a2;
B<long> b1, b2;
a1.value = 1;
a2.value = 2;
std::cout << a1+a2 << std::endl;
b1.value = 3l;
b2.value = 5l;
std::cout << b1+b2 << std::endl;
}
Obviously this works only for template classes with a value member.
For the "outside the class" version, base_op become
template <typename T>
struct base_op
{
friend auto operator+ (T const & t1, T const & t2)
{ return t1.value + t2.value; }
};
-- EDIT --
The OP asks
now I'm struggling to write their equivalent +=, -=, *=, /= operators within this same context... Any suggestions?
It's a little more complicated because they must return a reference to the derived object... I suppose that (for example) operator+=(), inside base_op, could be something as
T & operator+= (T const & o)
{
static_cast<T&>(*this).value += o.value;
return static_cast<T&>(*this);
}
Taking the answer provided by user max66 using CRTP and borrowing the concept of transparent comparators provided by the user SamVarshavchik within the comment section of my answer, I was able to adopt them and came up with this implementation design:
template<class T>
struct single_member_ops {
friend auto operator+(T const & lhs, T const & rhs)
{ return lhs.value + rhs.value; }
friend auto operator-(T const & lhs, T const & rhs)
{ return lhs.value - rhs.value; }
template<typename U>
friend auto operator+(T const& lhs, const U& rhs)
{ return lhs.value + rhs.value; }
template<typename U>
friend auto operator-(T const& lhs, const U& rhs )
{ return lhs.value - rhs.value;}
};
template<typename T>
struct A : public single_member_ops<A<T>>{
T value;
A() = default;
explicit A(T in) : value{in} {}
explicit A(A<T>& in) : value{in.value} {}
auto& operator=(const T& rhs) { return value = rhs; }
};
template<typename T>
struct B : public single_member_ops<B<T>> {
T value;
B() = default;
explicit B(T in) : value{in} {}
explicit B(B<T>& in) : value{in.value} {}
auto& operator=(const T& rhs) { return value = rhs; }
};
int main() {
A<int> a1(4);
A<int> a2;
A<int> a3{0};
a2 = 6;
a3 = a1 + a2;
B<double> b1(3.4);
B<double> b2(4.5);
auto x = a1 + b2;
auto y1 = a2 - b2;
auto y2 = b2 - a1;
return x;
}
You can see that this will compile found within this example on Compiler Explorer.
The additional templated operator allows for different types: A<T> and B<U> to use the operators even if T and U are different for both A and B provided there is a default conversion between T and U. However, the user will have to be aware of truncation, overflow & underflow, and narrowing conversions depending on their choice of T and U.
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;
}
I am using Boost-Operatators to construct a matrix class. (A toy project). However, I run into issues when I want to mix matrices of different element types.
Basically I have a template class Matrix<T>, where T is the element type of that matrix. I'm using Boost-Operators to define operators between instances of Matrix<T> (e.g. element-wise add), between Matrix<T> and T (e.g. scalar multiplication), and if possible also between Matrix<T> and Matrix<U> (e.g. real matrix plus complex matrix).
The boost operators support one, or two template arguments. One if you want operators between two objects of the same type, and two if you want mixed operators.
template<typename T>
class Matrix : boost::addable<Matrix<T>> // Add another matrix of same type.
boost::multiplyable2<Matrix<T>,T> // Scalar multiplication with a `T`.
However, I cannot give Matrix<U> as a second argument, because then my class would have two template arguments and the type would depend on which matrices I can operate with.
template<typename T, typename U>
class Matrix : boost::addable2<Matrix<T,U>,Matrix<U,?>> // Now I have two template arguments.
// That's certainly not what I want!
I also tried implementing my own version of boost::addable, but this didn't work either. The compiler complains about an uncomplete type.
template<class Derived>
class Addable {
template<class Other>
friend Derived operator+(Derived lhs, const Other &rhs) {
return lhs += rhs;
}
template<class Other>
friend Derived operator+(const Other &lhs, Derived rhs) {
return rhs += lhs;
}
};
Another approach was to define a cast constructor from Matrix<U> to Matrix<T>. However, now I have the issue, that those are two different types, and I don't get access to the private members. So, I either need to make more stuff public than I want to, or find a different way of doing this.
How would you implement such a thing?
The full Code
#include <cassert>
#include <utility>
#include <complex>
#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/operators.hpp>
typedef double Real;
typedef std::complex<Real> Complex;
template<typename T>
class Matrix : boost::addable<Matrix<T>>
{
public:
Matrix() = default;
template<typename U>
Matrix(const Matrix<U> &other)
: m_(other.m()), n_(other.n()),
data_(other.data_.begin(), other.data_.end()) { }
Matrix(size_t m, size_t n) : m_(m), n_(n), data_(m*n) { }
Matrix(size_t m, size_t n, const T &initial)
: m_(m), n_(n), data_(m*n, initial) { }
size_t m() const { return m_; }
size_t n() const { return n_; }
size_t size() const {
assert(m_*n_ == data_.size());
return data_.size();
}
const T &operator()(size_t i, size_t j) const { return data_[i*m_ + j]; }
T &operator()(size_t i, size_t j) { return data_[i*m_ + j]; }
void fill(const T &value) {
std::fill(data_.begin(), data_.end(), value);
}
Matrix &operator+=(const Matrix &other) {
assert(dim_match(other));
for (int i = 0; i < size(); ++i) {
data_[i] += other.data_[i];
}
return *this;
}
friend std::ostream &operator<<(std::ostream &o, const Matrix &m) {
if (m.size() == 0) {
o << "()" << std::endl;
return o;
}
for (int i = 0; i < m.m(); ++i) {
o << "( ";
for (int j = 0; j < m.n() - 1; ++j) {
o << m(i,j) << ", ";
}
o << m(i, m.n() - 1) << " )" << std::endl;
}
return o;
}
private:
bool dim_match(const Matrix &other) {
return n_ == other.n_ && m_ == other.m_;
}
private:
int m_, n_;
typedef std::vector<T> Store;
Store data_;
};
int main() {
Matrix<Real> A(2,3, 1.);
Matrix<Complex> B(2,3, Complex(0,1));
auto C = Matrix<Complex>(A) + B;
std::cout << A << std::endl;
std::cout << B << std::endl;
std::cout << C << std::endl;
}
This is how I'd do it: use a friend template function (see Operator overloading: The Decision between Member and Non-member):
template<typename T>
class Matrix
{
public:
template<typename> friend class Matrix;
And then later
template <typename T1, typename T2>
Matrix<typename std::common_type<T1, T2>::type>
operator+(Matrix<T1> const& a, Matrix<T2> const& b)
{
Matrix<typename std::common_type<T1, T2>::type> result(a);
return (result += b);
}
Note the use of common_type to arrive at a sensible resulting type (you might want to introduce your own trait there to cater for your specific requirements)
See it Live On Coliru
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?