I'm trying to declare a template method on a template class and it's not working for me.
It's better to explain by giving the code so here it is:
I have this class:
matrix.h
template <class T,int a,int b>
class Matrix {
private:
int x;
int y;
public:
class IllegalOperation();
template<T,int c,int d>
Matrix<T,a,b> operator+(const Matrix<T,c,d> m);
//...
}
matrix.cpp
template<class T,int a,int b>
template<T,int c,int d>
Matrix<T,a,b> Matrix<T,a,b>::operator+(const Matrix<T,c,d> m){
if(a!=c || b!=d) throw IllegalOperation();
// add matrices and return the result
}
I'd like this code to work for any 2 types of Matrix and Matrix where a,b,c and d can be different.
for example, I want this code to compile and return an error (in run time):
const Matrix<int, 3, 2> m1;
const Matrix<int, 7, 3> m2;
// init m1 and m2
m1+m2;
While this code should compile and run successfully:
const Matrix<int, 3, 2> m1;
const Matrix<int, 3, 2> m2;
// init m1 and m2
m1+m2;
However, when I try to compile the code above I get this error:
no match for âoperator+ in m1+m2
Change your code to this (not considering the things that I think might be wrong here, only changed it to make it compile)
#include <type_traits>
template <typename T,int a,int b>
class Matrix {
public:
template<typename T2, int c, int d>
Matrix<T,a,b> operator+(const Matrix<T2, c, d>& m) const;
private:
int x;
int y;
};
template <typename T,int a,int b>
template <typename T2, int c, int d>
Matrix<T, a, b> Matrix<T, a, b>::operator+(const Matrix<T2, c, d>&) const {
if(a != c || b != d) {
throw IllegalOperation{};
}
/*constexpr*/ if (!std::is_same<T, T2>::value) {
throw Error{};
}
return *this;
}
int main() {
const Matrix<int, 3, 2> m1{};
const Matrix<int, 7, 3> m2{};
m1 + m2;
return 0;
}
I've made a few changes here
The operator+ is const, you were trying to call a non const member function on a const object, would not work
The matrix parameter in the addition operator is now taken by reference
The operator+ cannot be defined in the .cpp file as mentioned in the comments, it must go in the header file (if you want to split up the interface and implementation, the best you can do is In the C++ Boost libraries, why is there a ".ipp" extension on some header files)
I usually like having the public section first since it gives the reader a better idea about the interface of the class.
Related
I am writing some template library (lets say a linear algebra library) and got the next complicated bug, that I am able to reproduce only on GCC (Clang and VC++ work as expected).
The library consists of generic template types like
template<class C, int N>
class Vector;
template<class C, int N, int M = N>
class Matrix;
with some default implementations those are not used.
Also there are a set of interface classes like these
template<class C, int N>
struct VecMulInterface
{
Vector<C, N> operator*(const Vector<C, N>& v)
{
return static_cast<Matrix<C, N, N>*>(this)->mul_impl(v);
}
};
template<class C, int N>
struct ScalMulInterface
{
Matrix<C, N, N> operator*(const C& c)
{
return static_cast<Matrix<C, N, N>*>(this)->mul_impl(c);
}
};
and respective implementations providers
template<class C, int N>
struct MulImpl
{
public:
Vector<C, N> mul_impl(const Vector<C, N>& v) const
{
return {}; // imagine some logic here
}
Matrix<C, N, N> mul_impl(const C& c) const
{
return {}; // imagine some logic here
}
};
Finally I have template specializations those use everything from above:
template<class C>
class Vector<C, 2>
{
public:
C items[2];
// ...
};
template<class C>
class Matrix<C, 2, 2>:
public VecMulInterface<C, 2>,
public ScalMulInterface<C, 2>,
public MulImpl<C, 2>
{
public:
C items[4];
// ...
};
I try to use them like this:
Matrix<int, 2, 2> m;
Vector<int, 2> v1, v2;
v2 = m * v1; // <- error
Now the GCC spawns an error "error: request for member ‘operator*’ is ambiguous".
But!
If I change the line with error such that I use overloaded function instead of 'operator*'
v2 = m.mul_impl( v1 ); // <- NO error
OR if instead of inheriting from respective interfaces I place the operators out-of-class like this:
template<class C, int N>
Vector<C, N> operator*(const Matrix<C, N, N>& m, const Vector<C, N>& v)
{
return m.mul_impl(v);
}
template<class C, int N>
Matrix<C, N, N> operator*(const Matrix<C, N, N>& m, const C& c)
{
return m.mul_impl(c);
}
everything works just fine. (VC++ and Clang seems to work correctly in all cases)
Could anyone explain the reason for such behavior? Is this a compiler bug or I stepped onto "undefined behavior" somewhere in the code?
Functions in different scopes don't overload. For the member operator* case, the two functions are in VecMulInterface and ScalMulInterface respectively, so they are in different scopes. In the other two cases, the two functions are in the same scope.
You can use a using declaration to promote them to the same scope:
template<class C>
class Matrix<C, 2, 2> :
public VecMulInterface<C, 2>,
public ScalMulInterface<C, 2>,
public MulImpl<C, 2>
{
public:
using VecMulInterface<C, 2>::operator*;
using ScalMulInterface<C, 2>::operator*;
// ...
};
A more elegant approach is to use friend functions in the interfaces:
template <class C, int N>
struct VecMulInterface
{
friend Vector<C, N> operator*(const Matrix<C, N, N>& m, const Vector<C, N>& v)
{
return m.mul_impl(m, v);
}
};
I am currently writing a matrix class that will be able to support any number of rows and columns through templates. I'm stuck on how go about preventing an invalid operation (i.e. number of columns for matrix 1 ≠ number of rows for matrix 2). I could of course store the number of rows and columns and check at run time, but optimally I'd like to make this check at compile time through a "wildcard" template argument.
In other words...
I want to do this:
template <typename T, int R, int C>
struct mat {
T matrix[R][C];
void operator *=(const mat<T, C, [can be anything]> &other) {
/* do operation */
}
};
Instead of this:
template <typename T, int R, int C>
struct mat {
T matrix[R][C];
int rows = R;
int columns = C;
void operator *=(const mat *other) {
if (columns != other->rows) {
/* error */
} else {
/* do operation */
}
}
};
Is this possible? If so, how do I do it?
This works for me
template <typename T, int R, int C>
struct mat {
T matrix[R][C];
template <int CC>
void operator *=(const mat<T, C, CC> &other) {
/* do operation */
}
};
int main()
{
mat<int, 2, 3> m1;
mat<int, 3, 4> m2;
m1 *= m2;
}
Define template《int K》mat《T,R,K》& operator*(const mat《T, C,K》& other)..
I would like to make a template class limit an overloaded method like this example:
template<int N>
class foo {
public:
void add(int a, int* b) {*b = a + N;}
int add(std::enable_if<N == 0, int> a, int b) {return a + b}
}
(Example changed to reflect complications not present in the original example.)
However, I am using Visual Studio, whose support for SFINAE (and thus enable_if) is still not very good. (I'm not sure if it would work in that simple example; in my actual situation I'm using std::enable_if on a class reference and using a member of that class, and it doesn't work.) The answer to this (which has essentially the same error message I got) suggested using tag dispatching as an alternative, but I'm not sure how that would work if I want the function to simply be unavailable at all with those argument types, or if I want to overload a constructor in this manner.
It needs to be made into a function template. And the condition in the enable_if needs to be made dependent on a template parameter of the function template so that it is not substituted into early.
template<int M = N,
class = typename std::enable_if<M == 0>::type>
int add(int a, int b) { return a + b; }
Usually I see std::enable_if used with return type
template<int N>
class foo {
public:
int add(int a)
{return a + N;}
template <int M = N>
typename std::enable_if<M == 0, int>::type add(int a, int b)
{return a + b}
}
This didn't work?
Another way can be the use of a base class (bar, in the following example) that define only add(int, int) and only in the required specialization.
template <int N>
struct bar
{ int add (int a, int b) = delete; };
template <>
struct bar<0>
{ int add (int a, int b) { return a + b; } };
template <int N>
struct foo : public bar<N>
{ using bar<N>::add; void add (int a, int * b) { *b = a + N; } };
int main()
{
foo<0> f0;
foo<1> f1;
int b { 0 };
f0.add(1, &b);
f0.add(1, 2);
f1.add(1, &b);
//f1.add(1, 2); // compilation error
}
Observe that the using bar<N>::add in foo is required because, otherwise, the add(int) in foo hide the add(int, int) in bar.
And that this using impose the int add (int a, int b) = delete; in the generic version of bar<N>.
If the name of the two function is different, say add2() for the version with 2 integer arguments, the example become simply as follows
template <int N>
struct bar
{ };
template <>
struct bar<0>
{ int add2 (int a, int b) { return a + b; } };
template <int N>
struct foo : public bar<N>
{ void add (int a, int * b) { *b = a + N; } };
int main()
{
foo<0> f0;
foo<1> f1;
int b { 0 };
f0.add(1, &b);
f0.add2(1, 2);
f1.add(1, &b);
//f1.add2(1, 2); // compilation error
}
No simple transformation of your code is legal. The signature of methods to template classes must be legal.
template<class D, bool> // false case
struct add_base {
void add(int* a, int b) {*a += b}
D*self(){return static_cast<D*>(this);}
D const*self()const{return static_cast<D const*>(this);}
};
template<class D>
struct add_base<D,true>:add_base<D,false> {
using base=add_base<D,false>;
using base::self;
using base::add; // for overload resolution
int add(int a, int b) {return a + b}
};
template<int N>
class foo: add_base<foo<N>, N==0> {
using base = add_base<foo<N>, N==0>;
template<class D, bool b>
friend class add_base<D, b>;// may be a syntax error here.
public:
using base::add;
};
here I assume the real add wants to use this; in this case use self() in its implementation.
There are other techniques using template parameters with default values, but their legality under a strict reading of the standard is questionable. The problem is the standard mandates all template functions have a valid specialization, and mostnuse of those techniques breaks that rule. There are different readings of the standard under which they may be legal.
You could also wait for c++2a concepts.
I have a matrix class:
template <typename T, const int N, const int M>
class TMatrixNxM
{
(...)
friend TMatrixNxM operator*(const TMatrixNxM&, const TMatrixNxM&);
(...)
}
Now, in maths, multiplying an NxM matrix with MxP matrix returns NxP matrix. So, I needed an operator that returns an NxP matrix, and takes an NxM and MxP matrices as arguments, like so:
template <typename T, const int N, const int M, const int P>
TMatrixNxM<T, N, P> operator*(const TMatrixNxM<T, N, M> &par_value1, const TMatrixNxM<T, M, P> &par_value2)
{
TMatrixNxM<T, N, P> result;
(...) //Calculate
return result;
}
When I test it:
TMatrixNxM<float, 2, 3> m1;
(...) //Set the values
TMatrixNxM<float, 3, 4> m2;
(...) //Set the values
TMatrixNxM<float, 2, 4> m3 = m1 * m2;
m1.print(); //Matrix class has a print function for testing
printf("\n");
m2.print();
printf("\n");
m3.print();
It works just like that. How and why exactly does this work? The overloadad operator takes an extra template argument, while the class takes only 3, and in the declaration I didn't specify anything. If I declare it like this, however:
template <typename T, const int N, const int M>
class TMatrixNxM
{
(...)
template<typename T, const int N, const int M, const int P> friend TMatrixNxM<N, P> operator*(const TMatrixNxM<N, M>&, const TMatrixNxM<M, P>&);
(...)
}
Then compiler complains that there are too few template arguments. I hope I'm not missing something obvious here.
Thanks!
EDIT
I see now that the "too few argument" complaint is aimed at the fact that I didn't include T too. Should have been TMatrixNxM< T, N, P >, etc.
Two things:
1) The compiler understands the difference between the template arguments to a class, and the template arguments to a function. You can have a class with 3 template arguments, and a function with 4.
So when you declare:
template <typename T, const int N, const int M, const int P>
TMatrixNxM<T, N, P> operator*(const TMatrixNxM<T, N, M> &par_value1, constXX TMatrixNxM<T, M, P> &par_value2)
you have defined a function that takes 4 template arguments. Then, when the compiler sees:
TMatrixNxM<float, 2, 4> m3 = m1 * m2;
the compiler deduces the 4 template arguments: T, N, M, and P. It deduces T = float, N = 2, M = 4, and P = comes from the third template argument of par_value2.
Also note that the template argument names for the function don't have to be the same as the template argument names on the class:
template <typename FOO, const int BAR, const int BAZ, const int QUX>
TMatrixNxM<FOO, BAR, QUX> operator*(const TMatrixNxM<FOO, BAR, BAZ> &par_value1, const TMatrixNxM<FOO, BAR, QUX> &par_value2)
2) In your second example, you are indeed missing a template argument. You are trying to return a TMatrixNxM but TMatrixNxM requires 3 arguments. It looks like it would work if you changed the return type to TMatrixNxM... which is what you did in the first part.
I'm implementing some classes for linear algebra operations on very small constant size vector and matrices.
Currenty, when I do :
MyMathVector<int, 3> a ={1, 2, 3};
MyMathVector<double, 3> b ={1.3, 2.3, 3.3};
std::cout<<"First = "<<a+b<<std::endl;
std::cout<<"Second = "<<b+a<<std::endl;
Then First = {2, 4, 6} and Second = {2.3, 4.3, 6.3}, because the second element is casted to the first element type by the compiler. Is there any "easy" way to provide the same kind of automatic casting like in native C++ : int+double=double, double+int=double ?
Thank you very much.
EDIT :
With the syntax given from answers, I got the operator+ working. But I tried the following syntax, and the compilation fails with the error : expected a type, got ‘std::common_type<T, TRHS>::type’
#include <iostream>
#include <type_traits>
template<class T> class MyClass
{
public:
MyClass(const T& n) : _n(n) {;}
template<class TRHS> MyClass<typename std::common_type<T, TRHS>::type> myFunction(const MyClass<TRHS>& rhs)
{
return MyClass<std::common_type<T, TRHS>::type>(_n*2+rhs._n);
}
T _n;
};
int main()
{
MyClass<double> a(3);
MyClass<int> b(5);
std::cout<<(a.myFunction(b))._n<<std::endl;
}
What is the problem of that syntax ?
Use std::common_type:
template <std::size_t s, typename L, typename R>
MyMathVector<typename std::common_type<L, R>::type, s> operator+(MyMathVector<L, s> const& l, MyMathVector<R, s> const& r)
{
// do addition
}
Ot in case of the member function (in the class body, where T and s are visible):
template <typename TRHS>
MyMathVector<typename std::common_type<T, TRHS>::type, s> operator+(MyMathVector<TRHS, s> const& rhs) const
{
// do addition
}
Use the std::common_type trait to figure out the correct result type for a mixed operation.
The linked page even has an example that's very similar to your case.
Absolutely; use decltype:
template<typename Other>
auto operator+(const MyMathVector<Other, size> &other)
-> MyMathVector<decltype(std::declval<T>() + std::declval<Other>()), size>;
As a non-member operator, it might be better to say what you mean by actually referencing a vector member:
template<typename size, typename L, typename R>
auto operator+(const MyMathVector<L, size> &l, const MyMathVector<R, size> &r)
-> MyMathVector<decltype(l[0] + r[0]), size>;