c++ - Implement template operator non-friend - c++

I have a simple generice arithmetic vector class and want to implement the * operator for scalar multiplication:
template<class Value_T, unsigned int N>
class VectorT
{
public:
typedef Value_T value_type;
typedef unsigned int size_type;
size_type GetNumElements() const { return N; }
// class member
// elements in the vector
value_type elements[N];
// the number of elements
static const size_type size = N;
};
// scalar multiplication
template<class Value_T, unsigned int N>
const VectorT<Value_T, N> operator*(const VectorT<Value_T, N>& v, Value_T s)
{
VectorT<Value_T,N> vTemp(v);
for (unsigned int i = 0; i < v.GetNumElements(); i++)
{
vTemp.elements[i] *= s;
}
return vTemp;
}
Using it like this ...
typedef VectorT<double, 3> Vec3;
int main(int argc, char* argv[])
{
Vec3 v;
Vec3 v2 = v * 2; // multiply with scalar int
return 0;
}
... gives compiler error C2782 (MSVC2012) that the template parameter Value_T for the * operator is ambiguous: int or double.
If I define the *operator within my class as friend function the error is gone and it works fine for scalar int or double. But actually there is no need here for friend declaration as the public interface of class VectorT is sufficient for the operator (In my real code I have the members privat and some public accessor methods).
I want the scalar multiplication work only for the Value_T type: For a VectorT<int, N> I want only integer values be given to the *operator. I further want the *operator being commutativ. That's why I don't implement it as a simple member function, where the lefthand operator is always of type VectorT.
How to implement * operator as non-member and non-friend here?

Look at the operator's definition
const VectorT<Value_T, N> operator*(const VectorT<Value_T, N>& v, Value_T s)
and on the line
Vec3 v2 = v * 2; // multiply with scalar int
operator* is called with parameters of type VectorT and int. So Value_T is double once and int the other time. You could multiply with 2.0 to resolve the ambiguity or add a third template parameter to the operator* definition:
template<class Value_T, unsigned int N, class ScalarType>
const VectorT<Value_T, N> operator*(const VectorT<Value_T, N>& v, ScalarType s)

The answers posted so far suggest giving an independent template parameter to the type of function parameter s. This is a viable approach, but not the only one.
Alternatively, a better solution might be to exclude your second argument from the template argument deduction process by intentionally placing it into non-deduced context
// scalar multiplication
template<class Value_T, unsigned int N>
const VectorT<Value_T, N> operator*(const VectorT<Value_T, N>& v,
typename VectorT<Value_T, N>::value_type s)
{
...
}
That way the compiler will deduce the template arguments from the type of v parameter, but not from the type of s parameter. And s will still have the proper type, just like you wanted it to.
The above approach takes advantage of the fact that your class template already provides a convenient inner typename value_type. In a more general case one can achieve the same by using an identity template
template <typename T> struct identity
{
typedef T type;
};
template<class Value_T, unsigned int N>
const VectorT<Value_T, N> operator*(const VectorT<Value_T, N>& v,
typename identity<Value_T>::type s)
{
...
}
The C++ standard library decided not to include std::identity template, since its functionality is apparently covered by std::decay and std::remove_reference. So, by using standard templates you can implement the general solution as
template<class Value_T, unsigned int N>
const VectorT<Value_T, N> operator*(const VectorT<Value_T, N>& v,
typename std::decay<Value_T>::type s)
{
...
}
The following article mentions this specific matter
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3766.html

First of, you could use std::array instead of implementing VectorT. Nevertheless, the problem you have is due to the fact that the integral literal 2 in the expression Vec3 v2 = v * 2; is of type int. Consequently, the compiler can't deduce to the overloaded operator* of yours, since as it is implemented it works only in the cases where your VectorT contains elements of the same type with the multiplier.
In order to overcome this, you could add an additional template argument to your overloaded operator* like the example below:
template<class Value_T1, class Value_T2, unsigned int N>
VectorT<Value_T1, N> operator*(const VectorT<Value_T1, N>& v, Value_T2 s)
{
VectorT<Value_T1, N> vTemp(v);
for(unsigned int i(0), sz(v.GetNumElements()); i < sz; ++i) {
vTemp.elements[i] *= s;
}
return vTemp;
}
LIVE DEMO

Related

Template constraints on operator overloading does not work as expected

#include <tuple>
#include <utility>
template<typename T>
struct is_tuple_like : std::false_type {};
template<typename... Ts>
struct is_tuple_like<std::tuple<Ts...>> : std::true_type {};
template<typename T, typename U>
struct is_tuple_like<std::pair<T, U>> : std::true_type {};
template<typename T>
concept tuple_like = is_tuple_like<T>::value;
template<tuple_like L, tuple_like R, int N = std::tuple_size_v<L>>
auto operator*(const L &lhs, const R &rhs) { return 0; }
enum { Enum };
int main()
{
Enum * Enum; // causes compilation error
return 0;
}
You can run the code here: http://coliru.stacked-crooked.com/a/f65e333060f40e60
I have defined a concept so-called tuple_like and overloaded operator*() using the concept.
Then, If I multiply enums, my overloaded operator*() for tuple_like is picked up and the compiler complains missing std::tuple_size for enum.
What did I do wrong here and how can I fix it without overload for each class templates - std::tuple and std::pair?
FYI, even if it's unusual, I cannot remove the part of multiplying enums because it's not my code.
Turn tuple_size_v into tuple_size::value to enable SFINAE
template<tuple_like L, tuple_like R, int N = std::tuple_size<L>::value>
auto operator*(const L &lhs, const R &rhs) { return 0; }
However, I don't see any value in declaring an extra template parameter N here. The type that satisfies tuple_like already guarantees that tuple_size_v is a valid value.
It would be more appropriate to move N into the function body
template<tuple_like L, tuple_like R>
auto operator*(const L &lhs, const R &rhs) {
constexpr auto N = std::tuple_size_v<L>; // guaranteed to work
// uses N below
}
Looks like gcc can't handle SFINAE for default values of template arguments. This workaround fixes it:
template<tuple_like L, tuple_like R, int N>
auto operator*(const L &lhs, const R &rhs) { return 0; }
template<tuple_like L, tuple_like R>
auto operator*(const L &lhs, const R &rhs) { return operator*<L, R, std::tuple_size_v<L>>(lhs, rhs); }

multidimensional array template class with expression templates

I am trying to understand expression templates by implementing my own multidimensional array class. Basically, I allocate a continuous chuck of memory and then I compute offsets with the () operator.
Now I want to overload the +,/,*,- with expression templates. The example illustrated in wikipedia is quite illustrative, but it assumes that the datablock is of type double. I would like to have the datatype as a template parameter. I have tried to implement this but I always fail. This is the code so far:
namespace ader{
template<class E, typename T> class vexp{
inline unsigned size()const{return static_cast<E const&>(*this).size();};
inline T operator[](const unsigned &i) const{ return static_cast<E const&>(*this)[i];}
};
// ***************************************************************************** //
template<class E1, class E2, typename T>
class vsum:
public vexp<vsum<E1,E2,T>,T>{
const E1 &_u;
const E2 &_v;
public:
vsum(const E1 &u, const E2 &v): _u(u), _v(v){};
inline T operator[](const unsigned &i)const {return _u[i] + _v[i];};
inline unsigned size()const{return _u.size();};
};
// ***************************************************************************** //
template<typename T, unsigned nDer> class aDer: public ader::vexp<aDer<T,nDer>,T>{
protected:
unsigned n;
T d[nDer+1];
public:
unsigned size()const{return n;};
T operator[](const unsigned &i) {return d[i];};
T &operator[](const unsigned &i)const{return d[i];};
aDer():n(nDer), d{0}{};
aDer(const T &in): n(nDer), d{0}{d[0] = in;};
aDer(const T &in, const unsigned &idx): n(nDer), d{0}{d[0] = in; d[idx+1] = T(1);};
template<template<typename,unsigned> class U> aDer(const vexp<U<T,nDer>,T> &in){
for(unsigned ii=0; ii<=nDer; ++ii) d[ii] = in[ii];
}
};
template< class E1, class E2, typename T>
vsum<E1,E2,T> operator+(const E1 &u, const E2 &v){return vsum<E1,E2,T>(u,v);};
};
The error message:
main2.cc: In function ‘int main()’:
main2.cc:15:27: error: no match for ‘operator+’ (operand types are ‘ader::aDer<float, 2>’ and ‘ader::aDer<float, 2>’)
ader::aDer<float,2> c= a+b;
Is there anything clearly wrong in the code?
EDIT1: the content of main2.cc:
#include "aut2.h"
#include <iostream>
using namespace std;
int main(){
ader::aDer<float,2> a(1.220334, 1);
ader::aDer<float,2> b(3.0, 0);
ader::aDer<float,2> c= a+b;
cerr<<c[0]<<endl;
}
Your operator+ has a non-deducible parameter T. You need to get rid of this parameter and infer the T from E1 and E2.
One way to achieve that would be to define your operator+ like this:
template <class E1, class E2>
auto operator+(const E1 &u, const E2 &v) -> vsum<E1, E2, decltype(u[0] + v[0])>
{
return { u,v };
}
Another way would be to get rid of the T parameter in all your classes altogether by using auto and decltype(auto) instead:
template <class E> class vexp {
...
inline decltype(auto) operator[](const unsigned &i) const { return static_cast<E const&>(*this)[i]; }
};
In the above code operator[] will return whatever type E::operator[] is returning.
Note that decltype(auto) and auto without a trailing return type specification is a C++14 feature.

Partial template specialization to unroll loops for specific sizes

I have written a matrix class which can take different sizes. Now I want to unroll loops for specific sizes. How should I do this?
The only way I can seem to get working is a child-class for 2-d. But this I would like to avoid, as it would result in much duplicate code.
For example:
#include <iostream>
template<class T, size_t M, size_t N>
class matrix
{
matrix<T,M,N>& operator*= (const matrix<T,M,N> &B);
};
template<class T, size_t M, size_t N>
matrix<T,M,N>& matrix<T,M,N>::operator*= (const matrix<T,M,N> &B)
{
// ...
return *this;
}
int main()
{
return 0;
}
Now I would like to add an implementation for the case that M = 2 and N = 2 where I unroll all loops to gain efficiency.
(I have timed the unroll in a previous implemenation, and it really does seem to make sense, in particular for more complicated operations then featured in this example.)
You can delegate operator*= to an overloaded function template. E.g.:
template<class T, size_t M, size_t N>
class matrix
{
public:
matrix<T,M,N>& operator*=(const matrix<T,M,N>&);
};
// Generic version.
template<class T, size_t M, size_t N>
void inplace_dot(matrix<T,M,N>& a, matrix<T,M,N> const& b);
// Overload for 2x2 matrix.
template<class T>
void inplace_dot(matrix<T,2,2>& a, matrix<T,2,2> const& b);
template<class T, size_t M, size_t N>
matrix<T,M,N>& matrix<T,M,N>::operator*=(const matrix<T,M,N>& b)
{
inplace_dot(*this, b);
return *this;
}

C++ introduce 'new' template arguments

I'm trying to make a reusable matrix class with the dimensions and type given in the template arguments. The struct itself is just:
template <unsigned int N, unsigned int M, typename T>
struct Matrix
{
T elements[N* M];
};
When I tried to implement matrix multiplication, I came to a problem that I need to introduce new template arguments. The size of the original matrix is N * M. The size of the second matrix is L * N and the result matrix is N * K. So the multiply function would look something like:
Matrix<N, K, T> Multiply(const Matrix<L, N, T>& other) {... }
But then I need to create a template for the function, so calling would become mat.Multiply<x, y>(mat2), which means that I have to specify things twice. Is there a way to avoid this? (something like Matrix<N, unsigned int K, T>)
Edit: I've tried this:
template <unsigned int K, unsigned int L>
Matrix<N, K, T> Multiply(const Matrix<L, N, T>& other)
And with this code I get an error saying no instance of function template matches the argument list:
Matrix<3, 2, int> mat;
Matrix<2, 3, int> mat2;
mat.Multiply(mat2)
By the way I'm using MSVC and Visual Studio.
so calling would become mat.Multiply<x, y>(mat2)
If the multiplication member function were a function template like so
template <unsigned int N, unsigned int M, typename T>
struct Matrix
{
template <unsigned int L>
Matrix<N, L, T> Multiply(const Matrix<M, L, T>& other) {... }
T elements[N * M];
};
then template argument deduction allows you to call the function like this:
mat.Multiply(mat2)
Note: you should probably consider implementing a non-member operator* too, to allow for this:
auto mat3 = mat * mat2;
It is normal that Multiply is also template.
Note that K == L for a multiplication.
template <unsigned int N, unsigned int M, typename T>
struct Matrix
{
template <unsigned int K>
Matrix<N, K, T> Multiply(const Matrix<M, K, T>& other) const {/*..*/}
T elements[N* M];
};
In the call, all template argument are deducible so you can call it that way:
int main()
{
const int N = 4;
const int M = 5;
const int K = 6;
using T = float;
Matrix<N, M, T> rhs;
Matrix<M, K, T> lhs;
Matrix<N, K, T> res = rhs.Multiply(lhs);
}

C++ operator* overloading

I have the following Matrix class that seems to be working well so far
template<typename T, std::size_t M, std::size_t N>
class Matrix
{
public:
Matrix(const std::initializer_list<std::initializer_list<T>> m)
{
// snip
}
T& operator()(const std::size_t i, const std::size_t j)
{
return m_data.at(i + j * N);
}
const T& operator()(const std::size_t i, const std::size_t j) const
{
return m_data.at(i + j * N);
}
Matrix<T,M,N> operator*(const T n)
{
// snip
}
private:
std::array<T, M * N> m_data;
};
However the overloaded operator* only allows scalar multiplication if the scalar is on the right hand side of the operator. I would like to allow this operation even if the scalar is on the left hand side of the operator, so I tried adding this to the Matrix.hpp file:
template<typename T, std::size_t M, std::size_t N>
Matrix<T,M,N> operator*(const T lhs, const Matrix<T,M,N> &rhs)
{
return rhs * lhs;
}
But this gives me the following error:
In file included from test.cpp:1:0:
Matrix.hpp: In instantiation of ‘Matrix<T, M, N> operator*(T, const Matrix<T, M, N>&) [with T = double; long unsigned int M = 3ul; long unsigned int N = 3ul]’:
test.cpp:21:13: required from here
Matrix.hpp:137:13: error: passing ‘const Matrix<double, 3ul, 3ul>’ as ‘this’ argument of ‘Matrix<T, M, N> Matrix<T, M, N>::operator*(T) [with T = double; long unsigned int M = 3ul; long unsigned int N = 3ul]’ discards qualifiers [-fpermissive]
return rhs * lhs;
If I remove const from the Matrix rhs parameter the code compiles and works correctly. I would like to understand why the code does not compile with the const in place?
You need to make the operator* free functions. (You'll need two of
them, one with the scalar on the right, and one with it on the left.)
You probably also want an operator*=; it may be convenient to use this
operator to implement the two operator*.
When you write operator as the member method then the first argument is always "this" instance of the class. If you want to write scalar * matrix then you must write the operator as non-member function. It is usually done as friend method.
template<typename T>
Matrix<T> operator*(T const& n, Matrix<T> m)
{
// snip
}
template<typename T>
Matrix<T> operator*(Matrix<T> m, T const& n)
{
return n * m;
}