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);
}
};
Related
I am implementing my static multi-dimentional vector class. I am using std::array as the underlying data type.
template <typename T, std::size_t N>
class Vector {
private:
std::array<T, N> data;
};
I want to make my class downwards-compatible, so I am writing this:
template <typename T, std::size_t N>
class Vector : public Vector<T, N-1>{
private:
std::array<T, N> data;
};
template <typename T>
class Vector<T, 0> {};
My goal is that when one instance is used in downwards-compatible mode, its underlying data should be able to be reliably accessed:
template<typename T, std::size_t N>
T& Vector<T, N>::operator[](int i) {
// Do boundary checking here
return this->data[i];
}
void foo(Vector<int, 3>& arg) {
arg[1] = 10;
}
Vector<int, 5> b;
foo(b);
// Now b[1] should be 10
There are two points here:
Vector<T, 5> should be accepted by foo(), Vector<T, 2> should be rejected.
Changes to b[0] through b[2] in foo() should pertain. b[3] and b[4] should not be accessible in foo().
How can I achieve that?
How about a simple read wrapper around std::array<> itself?
template<typename T, std::size_t N>
struct ArrayReader {
public:
// Intentionally implicit.
template<std::size_t SRC_LEN>
ArrayReader(std::array<T, SRC_LEN> const& src)
: data_(src.data()) {
static_assert(SRC_LEN >= N);
}
private:
T const* data_;
};
void foo(ArrayReader<float, 3>);
void bar() {
std::array<float, 4> a;
std::array<float, 2> b;
foo(a);
foo(b); //BOOM!
}
Of course, you can easily substitute std::array for your own type, this is just an example of the principle.
Have array keep the data, and then create additional non-owning class, e.g. array_view that will keep only a pointer. It will have generic constructor that accepts the array, and will have a static_assert to check the sizes.
Here's how I would approach this:
template <class Container, std::size_t size>
struct range_view
{
range_view(Container * p): container(p) { assert(size <= p->size()); }
auto & operator[](std::size_t i) { return (*container)[i]; }
private:
Container * container;
};
Then you simply define foo as:
template <class C>
void foo(range_view<C, 3> c)
{
c[1] = 1;
}
Here's something that is closest to what I think you would need.
Make Vector a viewer/user of the data, not the owner of the data.
#include <array>
template <typename T, std::size_t N, std::size_t I>
class Vector : public Vector<T, N, I-1>
{
public:
Vector(std::array<T, N>& arr) : Vector<T, N, I-1>(arr), arr_(arr) {}
T& operator[](int i) {
return arr_[i];
}
private:
std::array<T, N>& arr_;
};
template <typename T, std::size_t N>
class Vector<T, N, 0ul>
{
public:
Vector(std::array<T, N>& arr) : arr_(arr) {}
private:
std::array<T, N>& arr_;
};
void foo(Vector<int, 5, 3>& arg) {
arg[1] = 10;
// Can't find a way to make this a compile time error.
arg[3] = 10;
}
#include <iostream>
int main()
{
std::array<int, 5> arr;
Vector<int, 5, 5> b(arr);
foo(b);
std::cout << b[1] << std::endl;
}
Here's a demonstration of how to implement the Vector class that you tried in your question. At each level you only store 1 value instead of an array and that way when you compose all your N Arrays together you get space for N values. Of course then calling operator[] gets tricky, which is the meat of what I wanted to demonstrate.
#include <utility>
template <class T, std::size_t N>
struct Array : Array<T, N-1>
{
T & operator[](std::size_t i)
{
return const_cast<T&>((*const_cast<const Array*>(this))[i]);
}
const T & operator[](std::size_t i) const
{
return Get(i, std::make_index_sequence<N>());
}
template <std::size_t i>
const T & Geti() const
{
return static_cast<const Array<T, i+1>&>(*this).GetValue();
}
const T & GetValue() const { return value; }
template <std::size_t ... indices>
const T & Get(std::size_t i, std::integer_sequence<std::size_t, indices...>) const
{
using X = decltype(&Array::Geti<0>);
X getters[] = { &Array::Geti<indices>... };
return (this->*getters[i])();
}
template <std::size_t i, class = typename std::enable_if<(i <= N)>::type>
operator Array<T, i>&() { return (Array<T, i>&)*this; }
private:
T value;
};
template <class T>
struct Array<T, 0>{};
void foo(Array<float, 3> & a) { a[1] = 10; }
int main()
{
Array<float, 10> a;
foo(a);
}
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.
I haven't been doing this for a while. I basically have a class
template <int L>
class MyInteger {
//code
};
And specifically I'd like to implement something like (as a method)
template <int L, int M, int N>
MyInteger<N> MyInteger<L>::operator+(const MyInteger<M>& x) const;
But I want to restrict N to be the max(L,M) is there a way to achieve that using template metaprogramming? I was thinking the use of enable_if and maybe SFINAE could allow me to achieve what I want, but I'm not entirely sure how to do that.
Do you just want it to be the max of the two? Or do you want it to be no more than the max of the two? If you want it to always be the max I'd create a utility struct like below and set N as
template<int L,int M>
struct MaxInteger
{
public:
static const int value = L > M ? L : M;
};
Then implement it like this.
template<int L, int M>
MyInteger<MaxInteger<L,M>::value> MyInteger<L>::operator+(const MyInteger<M>& x) const;
Edit: As requested a constexpr implementation.
constexpr int constMax(constexpr int a,constexpr int b) {return a > b ? a : b;}
Then implement like this
template<int L, int M>
MyInteger<constMax(L,M)> MyInteger<L>::operator+(const MyInteger<M>& x) const;
or you can do it without the struct
template<int L, int M>
MyInteger<L > M ? L : M> MyInteger<L>::operator+(const MyInteger<M>& x) const;
In C++14 (as you tagged the question) you can simply do this:
#include <type_traits>
template <int L>
class MyInteger {};
template <int L, int M>
constexpr auto operator+(const MyInteger<L> &lhs, const MyInteger<M> &rhs) {
return MyInteger<(L > M ? L : M)>{};
}
int main() {
constexpr MyInteger<0> m1;
constexpr MyInteger<1> m2;
static_assert(std::is_same<decltype(m1 + m2), MyInteger<1>>::value, "!");
}
That is, use the auto return type and let the compiler deduce it for you.
Then, in the body of the function, you can pick the max value up and create the right type.
If you prefer to be explicit about the return type, another possible solution is this:
template <int L, int M>
constexpr MyInteger<(L > M ? L : M)> operator+(const MyInteger<L> &lhs, const MyInteger<M> &rhs) {
return {};
}
No need to use sfinae anywhere.
I want to define conversion to float for matrix<1, 1>. I have trouble figuring out how to actually define it. If I make it a global function
template<typename T>
inline operator T(const matrix<T, 1, 1> &m){ return m(0, 0); }
I get "operator.. must be a non static member function"
I can of course define it as member for the generic matrix template but then it will be defined for all matrices - which is not what I want. I want it to be defined only for the specific case of 1x1 matrix.
You have to specialize a class for that, for example:
template <typename Base, typename T, std::size_t W, std::size_t H>
struct MatrixConversion
{ /*Empty*/ };
template <typename Base, typename T> struct MatrixConversion<T, 1u, 1u>
{
operator const T&() const { return static_cast<const Base&>(*this).m[0][0]; }
};
template <typename T, std::size_t W, std::size_t H>
struct Matrix : MatrixConversion<Matrix<T, W, H>, T, W, H>
{
// Your code
};
composition plus specialisation would be the most maintainable approach.
You did not specify the number of dimensions in your matrix template class, so I have assumed it can be variadic.
#include <cstdint>
#include <utility>
//
// forward-declare class template for convenience.
//
template<class T, std::size_t...Dimensions>
struct matrix;
//
// classes to figure out the storage requirements of a multi-dimensional
// matrix
//
template<class T, std::size_t...Dimensions> struct storage;
template<class T, std::size_t N>
struct storage<T, N>
{
using type = T[N];
};
template<class T, std::size_t...Rest, std::size_t N>
struct storage<T, N, Rest...>
{
using less_dimension_type = typename storage<T, Rest...>::type;
using type = less_dimension_type[N];
};
//
// functions for dereferencing multi-dimensional arrays
//
template<class Array, class Arg>
decltype(auto) deref(Array& array, Arg&& arg)
{
return array[arg];
}
template<class Array, class Arg, class Arg2>
decltype(auto) deref(Array& array, Arg&& arg, Arg2&& arg2)
{
return array[arg][arg2];
}
template<class Array, class Arg, class...Args>
decltype(auto) deref(Array& array, Arg&& arg, Args&&...args)
{
return deref(deref(array, arg), std::forward<Args>(args)...);
}
//
// prototype for operations we want to conditionally apply
//
template<class Matrix>
struct matrix_conditional_ops
{
// in the general case, none
};
//
// compose the matrix class from conditional_ops<>
//
template<class T, std::size_t...Dimensions>
struct matrix
: matrix_conditional_ops<matrix<T, Dimensions...>>
{
template<class...Dims>
decltype(auto) at(Dims&&...ds)
{
return deref(_data, std::forward<Dims>(ds)...);
}
template<class...Dims>
decltype(auto) at(Dims&&...ds) const
{
return deref(_data, std::forward<Dims>(ds)...);
}
typename storage<T, Dimensions...>::type _data;
};
//
// define the condition operations for the <T, 1, 1> case
//
template<class T>
struct matrix_conditional_ops<matrix<T, 1, 1>>
{
using matrix_type = matrix<T, 1, 1>;
operator T const() { return static_cast<matrix_type const&>(*this).at(0,0); }
};
int main()
{
matrix<double, 1, 1> m11;
m11.at(0,0) = 6.0;
double d = m11;
matrix<double, 2, 2> m22;
// compile error:
// double d2 = m22;
// bonus points:
matrix<double, 3, 5, 2, 7> mxx;
mxx.at(2, 4, 1, 6) = 4.3; // probably needs some compile-time checking...
}
someone may want to check my logic for the array packing/dereferencing...
Jarod and Richard already gave you the best answers in my opinion, they scale well to any number of operators with all kinds of restrictions.
However, if you cannot afford to redesign your class, or all you need is a quick and dirty opertor T() you can get away with the following
template<typename T, std::size_t N1, std::size_t N2>
struct Matrix
{
T m[N1][N1];
operator T()
{
static_assert(N1 == 1 && N2 == 1, "Only applicable to scalars");
return m[0][0];
}
};
Which is live here.
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>;