I have a class that represents a quantity that can only take on integer or half-integer values, and so stores its value internally as an integer that is twice the value. That is: a value of 0.5 is stored as 1, 1 as 2, 1.5 as 3, etc. Let's call it class A with a stored value int TwoA_.
This forces the A values to be properly integer or half-integer. Since I often need to use them as their true values, I have naturally made a cast to double operator that simply returns 0.5 * TwoA_.
However, very frequently I need to use twice the value. I thought it would be neat to code 2 * a (a being an object of type A) to directly return the value TwoA_ stored inside a.
Ideally, I'd like to make an operator that only does this when multiplied by 2 from the left. All other situations would be covered by the implicit cast.
Is there any way to do this in c++? I though of some sort of templated multiplication operator.
The simple solution of just defining
friend double operator*(int lhs, const A& rhs)
{ return (lhs == 2) ? rhs.TwoA_ : lhs * static_cast<double>(rhs); }
is not what I'm looking for. 2 * a is guaranteed to be an int (but generically an_int * a is not), and I would like to return an int.
This is a question of curiosity; if you only want to comment "why would you want to do that?" (or some variation thereof), please hold your tongue.
An edit: I meant multiplication on the left by the integer literal 2 (not an integer variable which is tested to see if it has the value 2)
Understanding your question to be if you can overload the * operator such that it returns a different data type based on the value of one of the parameters, the short answer is: No.
The long answer: No, but maybe yes.
double operator*(const int lhs, const A& rhs);
That operator would have to know AT COMPILE TIME if lhs is 2 or not, and that cannot be guaranteed. Which means a decision as to how to handle the case of lhs being 2 or not must be done at runtime. But the data type that an operator returns must be known at compile time...
double operator*(const some_type_1& lhs, const A& rhs);
int operator*(const some_type_2& lhs, const A& rhs);
This would get you two different return types, but only with compile-time knowledge of what those argument types are.
template<int T>
struct special_number{};
//...
template<>
int operator*(const special_number<2>&, const A& rhs){
return rhs.TwoA_;
}
template<int T>
double operator*(const special_number<T>&, const A& rhs){
return (static_cast<double>(rhs) / 2.0) * T;
}
//usage
int answer1 = special_number<2> * my_a_object;
double answer2 = special_number<3> * my_a_object;
This would do just that.
struct two_t {
constexpr two_t() {};
template<class T>
constexpr operator T()const{return 2;}
};
constexpr two_t two;
Now:
friend double operator*(two_t lhs, const A& rhs)
{ return rhs.TwoA_; }
friend double operator*(const A& lhs, two_t lhs)
{ return lhs.TwoA_; }
is about the best you can do.
The type of an expression is not dependent on the values, except in the special case where the constant 0 can be converted to a pointer and can cause different overload resolutions.
That special case cannot be leveraged to make 2 special when passed as an argment to *.
Now
constexpr std::ptrdiff_t from_digits(std::integer_sequence<char>) {
return 0;
}
constexpr std::ptrdiff_t compile_time_pow( std::ptrdiff_t base, std::size_t exp ) {
return exp ? base * compile_time_pow( base, exp-1 ) : std::ptrdiff_t(1);
}
template<char c0, char...cs>
constexpr std::ptrdiff_t from_digits(std::integer_sequence<char, c0, cs...>) {
return
compile_time_pow(10, sizeof...(cs))*(c0-'0')
+ from_digits( std::integer_sequence<char, cs...>{} );
}
template<char...cs>
constexpr auto operator"" _integer() {
return std::integral_constant<std::ptrdiff_t, from_digits( std::integer_sequence<char, cs...>{} )>{};
}
Now 2_integer is a compile_time std::ptrdiff_t of value 2, with the value encoded in its type.
Thus 2_integer * a could be overridden to return a differnet type than 3_integer * a, or 2 * a.
Related
For trivial types, compilers can optimize arithmetic expressions into a new expression, with the same result, that requires less instructions in order to compute it. For example, if a, b are int, then the expression int c = a * a + b * a would be computed as (a + b) * a, which saves an instruction.
Is there a way to tell the compiler to perform this optimization for custom types? E.g., if A, B are matrices, then computing A*A + A*B would be factored as A*(A+B) (at compile time), which saves about n2 operations during runtime.
First note, A*A + A*B != (A+B)*A for matrices, not even close. It's A*(A+B) and that's not the same as matrix multiplication is not commutative. That said, what you're asking for, as a conceptual thing, is feasible.
This is not a complete answer, just a heads up. As #JerryJeremiah correctly wrote, you might use expression templates for this. First for your matrix class, instead of operators implementing evaluation of expressions, you return an unevaluated context: (here I show value scemantics, of course, you might implement it using references/pointers)
template<typename LHS, typename RHS, char op>
struct OperatorContext {
static constexpr char operator = op;
const LHS lhs;
const RHS rhs;
};
// inside Matrix {
template<typename LHS, typename RHS, char op>
friend auto operator+(const Matrix& lhs, OperatorContext<LHS, RHS, op>& rhs) {
return OperatorContext<Matrix, OperatorContext<LHS, RHS, op>, '+'>{lhs, rhs};
}
template<typename LHS, typename RHS, char op>
friend auto operator+(OperatorContext<LHS, RHS, op>& lhs, const Matrix& rhs) {
return OperatorContext<Matrix, OperatorContext<LHS, RHS, op>, '+'>{lhs, rhs};
}
friend auto operator+(const Matrix& lhs, const Matrix& rhs) {
return OperatorContext<Matrix, Matrix, '+'>{lhs, rhs};
}
// similarly for other operators
// }
// furthermore, you need similar operators for 2 OperatorContext arguments
Then, you can implement assignment operator to Matrix from various OperatorContext<> versions. Here, you might do the optimization, as you have complete type info. Note that this only works until you assign to a variable. E.g.:
// inside Matrix {
Matrix& operator=(OperatorContext<OperatorContext<Matrix, Matrix, '*'>, OperatorContext<Matrix, Matrix, '*', '+'> other) {
if (other.lhs.lhs == other.rhs.lhs) { // preferably compare-by-address
*this = other.lhs.lhs * (other.lhs.rhs + other.rhs.rhs)
} else {
*this = other.lhs.lhs * other.lhs.rhs + other.rhs.lhs * other.rhs.rhs;
}
return *this;
}
// }
I want to construct a class that contains several Eigen Matrices or Vectors. I want the objects to behave as mathematical vectors: therefore I want to overload +, - and *(by a scalar). I want to do very many linear combinations of these objects, so I would like to implement it in a way that it takes full advantage of Eigen and creates as few copies and temporaries as possible.
I usually follow the recommendations in What are the basic rules and idioms for operator overloading? but they require to pass some of the object by value rather than reference. Eigen "dislikes" when matrices are passed by value.
Below is my attempt (I overload only + for shortness) where I avoid passing by value in the overloading of + and instead I use the named return value optimization (NRVO):
template <int N> class myClass {
public:
Eigen::Matrix<double, N, N> mat = Eigen::Matrix<double, N, N>::Zero();
Eigen::Matrix<double, N, 1> vec = Eigen::Matrix<double, N, 1>::Zero();
public:
myClass(){}
myClass(Eigen::Matrix<double, N, N> & t_mat,Eigen::Matrix<double, N, 1> &t_vec) : mat (t_mat), vec(t_vec){ }
myClass(const myClass & other): mat(other.mat), vec(other.vec) {};
myClass& operator+=(const myClass& rhs){
mat += rhs.mat; vec += rhs.vec;
return *this;
}
public:
enum { NeedsToAlign = (sizeof(mat)%16)==0 || (sizeof(vec)%16)==0 };
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
};
template <int N> myClass<N>& operator+( const myClass<N>& lhs, const myClass<N>& rhs )
{
myClass<N> nrv( lhs );
nrv += rhs;
return nrv;
}
Is this the best solution? Fastest?
As a final short question: it would be nice to use Boost/operators (https://www.boost.org/doc/libs/1_54_0/libs/utility/operators.htm) to easily complete the set of operator overloading. Can I use that, or would that cause problems? I guess it will implement binary operations passing the first argument by value.
I tried to solve the problem by myself. I tried several versions and compared them with directly summing Eigen vectors.
The first strategy follows What are the basic rules and idioms for operator overloading?:
using realValueType = double;
const int NDim = 1000000;
using InternalVecType = Eigen::Matrix<realValueType, Eigen::Dynamic, 1>;
class MyVec {
public:
InternalVecType vec;
// ... Other properties
public:
// Constructors
MyVec(): vec(InternalVecType::Random(NDim,1)) {} // Initialises as random, just for testing
MyVec(const InternalVecType& other): vec(other) {};
MyVec(const MyVec& other): vec(other.vec) {}; // Copy constructor
MyVec(MyVec&& other){vec.swap(other.vec);} // Move constructor
// Arithmetic
MyVec& operator=(MyVec other){vec.swap(other.vec);return *this;} // Copy-and-Swap
MyVec& operator+=(const MyVec& other) {vec+=other.vec; return *this;}
friend MyVec operator+(MyVec lhs, const MyVec& rhs) { lhs += rhs; return lhs;}
};
The second version uses NRVO
class MyVecNRVO {
public:
InternalVecType vec;
// ... Other properties
public:
// Constructors
MyVecNRVO(): vec(InternalVecType::Random(NDim,1)) {} // Initialises as random, just for testing
MyVecNRVO(const InternalVecType& other): vec(other) {};
MyVecNRVO(const MyVec& other): vec(other.vec) {}; // Copy constructor
MyVecNRVO(MyVec&& other){vec.swap(other.vec);} // Move constructor
// Arithmetic
MyVecNRVO& operator=(MyVecNRVO other){vec.swap(other.vec);return *this;} // Copy-and-Swap
MyVecNRVO& operator+=(const MyVecNRVO& other) {vec+=other.vec; return *this;}
friend MyVecNRVO operator+(const MyVecNRVO& lhs, const MyVecNRVO& rhs) {
MyVecNRVO nrv(lhs); nrv += rhs; return nrv;}
};
My third version uses (probably clumsily) expression templates
struct Add { static InternalVecType apply(InternalVecType lhs, InternalVecType rhs) {return lhs+rhs;} };
template<class E1, class E2, class Op> struct ComplexExpr {
E1 l_;
E2 r_;
ComplexExpr(E1 l, E2 r) : l_(l), r_(r) {}
InternalVecType getvec(){return Op::apply(l_.getvec(), r_.getvec());}
};
template<class E1, class E2> ComplexExpr<E1, E2, Add> operator+ (E1 e1, E2 e2) {
return ComplexExpr<E1, E2, Add>( e1, e2 );
}
class MyVecT {
public:
InternalVecType vec;
// ... Other properties
public:
// Constructors
MyVecT(): vec(InternalVecType::Random(NDim,1)) {} // Initialises as random, just for testing
MyVecT(const InternalVecType& other): vec(other) {};
// template<> MyVecT(
InternalVecType getvec(){return vec;};
};
To test it I created 15 vectors of types InternalVecType (meaning the Eigen type not wrapped in my class), MyVec, MyVecNRVO, and MyVecT and summed them in a single line.
What I have noticed is that the first version is not only the fastest, but also as fast as directly adding the Eigen vectors in a single line! NRVO is around 5 times slower, while my attempt at expression templates 100 times slower (ouch! but in my defence, it is my very first attempt ever :D).
It seems that the first option is not only the best, but also the optimal. Maybe a better implementation of expression templates could achieve a better speed, but since the first option is as fast as the raw summation, it does not seem worth to go in that direction. Any comment is welcome.
If I have a generic struct/class:
template<typename T>
struct Container
{
T value;
Container(const Value& value) : value(value) { }
};
And I want to perform an operation on two of them:
template<typename T, typename U>
Container<T> operator+(const Container<T>& lhs, const Container<U>& rhs)
{
return Container<T>(lhs.value + rhs.value);
}
The problem is that if lhs is of the type Container<int> and rhs is of the type Container<float>, then I'll get a Container<int> back. But if I were to do auto result = 2 + 2.0f, then result would of of type float. So the behavior is inconsistent between builtin types and custom types.
So how would I take the operator+ overload and make it return Container<float>, much like how C++ handles arithmetic promotion with builtin types?
As far as you use one of the two types of the template, you risk to induce a cast on the result of the sum. As an example, if you accidentally choose int as your target type, even though the sum results in a float, it will be cast down to the chosen type.
Anyway, starting with C++11, you con rely on the decltype specifier as in the example above (or at least, you can do that if Container::T and Container::U are a types for which the + operator is defined).
I used also the auto specifier as return value for the operator+, for it is at our disposal starting from C++14 and it's really useful indeed.
It follows the working example above mentioned:
#include <iostream>
#include <vector>
template<typename T>
struct Container
{
T value;
Container(const T& value) : value(value) { }
};
template<typename T, typename U>
auto operator+(const Container<T>& lhs, const Container<U>& rhs)
{
return Container<decltype(lhs.value+rhs.value)>{lhs.value + rhs.value};
}
int main()
{
Container<int> c1{1};
Container<float> c2{0.5};
std::cout << (c1+c2).value << std::endl;
}
Given the following code:
struct Zero{};
template<typename T>
Zero operator*(const Zero& zero, const T& other){return Zero();}
struct Identity{};
template<typename T>
T operator*(const T& other, const Identity& id){return T();}
Now, I want to use this code like this:
Zero z;
Identity id;
int i = 5;
z * i; // ok
i * id; // ok
z * id; //error: ambiguity in function resolution
The compiler will not be able to resolve the operator in the last line, because both functions could be used. In fact in this case I do not care which function is used, since they have the same functionality. In both cases Zero() will be returned as expected.
My Question: How can I express that in this case any of the functions are ok to use?
Just add one more overload (which is not a template whatsoever):
Zero operator*(const Zero& other, const Identity& id){return Zero();}
Just use SFINAE to remove the first template from consideration if T is Identity:
template<typename T> auto operator*(const Zero& zero, const T& other)
-> typename std::enable_if<!std::is_same<T, Identity>::value, Zero>::value
{return {};}
I have the following in my header file:
template<typename T>
class rational {
private:
T num;
T denom;
T gcd(T x, T y);
public:
rational(T num, T denom);
rational(T wholeNumber);
template<typename U>
friend inline rational<U> operator *(const rational<U> &lhs, const rational<U> &rhs);
}
template<typename T>
rational<T>::rational(T whole) {
this->num = whole;
this->denom = 1;
}
template<typename T>
rational<T> operator *(const rational<T> &lhs, const rational<T> &rhs) {
return rational<T>(lhs.num * rhs.num, lhs.denom * rhs.denom);
}
And the following in my main:
rational<int> x(6), y(2);
rational<int> product = y * x; // this works
rational<int> product2 = 2 * x; // this doesn't
The first product works, but the second one gives me "error: no match for ‘operator*’ in ‘2 * x’". Why? Since there is a constructor available that takes only the 2 as an argument, shouldn't that be automatically called? If not, how else would I overload the operator to have both of these work?
Thanks.
I'm not sure why the compiler will not invoke the single-argument constructor implicitly on 2 in order to produce a rational, but my guess is that the inference mechanism is simply broken when templates are involved.
One workaround (if no one knows how to fix the implicit constructor issue) is to define an additional multiply operators like thus:
template<typename T>
rational<T> operator *(const T &lhs, const rational<T> &rhs) {
return rational<T>(lhs * rhs.num, rhs.denom);
}
template<typename T>
rational<T> operator *(const rational<T> &lhs, const T &rhs) {
return rational<T>(lhs.num * rhs, lhs.denom);
}
This will also perform better, if you are writing high-performance code using rationals in an inner loop somewhere.
2 * x;
is analogical equivalent to calling of,
int::operator*(const rantional<int>&)
2 is an int and it doesn't have operator * overloaded for const rational<int>&; thus you get compiler errors.
The correct way is to have:
rational<int> product2 = rational<int>(2) * x; // ok