I've got the following code for function traits:
template<typename T>
struct function_traits;
template<class F>
struct function_traits;
// function pointer
template<class R, class... Args>
struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)>
{};
template<class R, class... Args>
struct function_traits<R(Args...)>
{
using return_type = R;
static constexpr std::size_t arity = sizeof...(Args);
template <std::size_t N>
struct argument
{
static_assert(N < arity, "error: invalid parameter index.");
using type = typename std::tuple_element<N,std::tuple<Args...>>::type;
};
};
// member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...)> : public function_traits<R(C&,Args...)>
{};
// const member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...) const> : public function_traits<R(C&,Args...)>
{};
// member object pointer
template<class C, class R>
struct function_traits<R(C::*)> : public function_traits<R(C&)>
{};
and another Matrix class with the following signature:
#include <iostream>
/**
* @struct MatrixDims
* @brief Matrix dimensions container
*/
typedef struct MatrixDims
{
int rows, cols;
} MatrixDims;
/**
* Matrix class (only for 2D matrices)
*/
class Matrix
{
public:
const std::string errInvalidDims = "Error: Invalid matrices dimensions for this operation.";
const std::string errIndexOutOfRange = "Error: Index out of range.";
const std::string errFailToLoadMatrix = "Error: Failed to load elements to matrix from file.";
/**
* Matrix object constructor
* @param n Amount of rows
* @param m Amount of columns
*/
Matrix(int n, int m);
/***
* Copy Constructor for Matrix
* @param m Matrix to be copied
*/
Matrix(const Matrix &m);
/**
* default C'tor
*/
Matrix(): Matrix(1,1) {};
/***
* Destructor for Matrix
*/
~Matrix();
//########################## Operator Overloading Functions ########################################
/**
* Operator overload for = operator
* @param m Matrix to be copied
* @return reference to calling object
*/
Matrix& operator=(const Matrix &M);
/**
* Operator overload for Matrix multiplication.
* @param M: right side Matrix
* @return new matrix with new dimensions
* (Num of rows = number of rows of calling matrix, Num of Columns = num of columns as right side matrix)
*/
Matrix operator*(const Matrix &M) const;
/**
* Operator Overload for Matrix addition, on invalid
* @param M Right side Matrix
* @return new matrix with same dimension as calling matrix
*/
Matrix operator+(const Matrix &M) const;
/**
* Operator Overload for Matrix +=
* @param M Right side Matrix
* @return reference to the calling matrix after the addition
*/
Matrix& operator+=(const Matrix &M);
/**
* Overload to () operator, allows access and change of the i,j coordinate
* @param i - ith row
* @param j - jth column
* @return reference to the value stored in the i,j coordinate
*/
float& operator()(int i, int j);
/**
* Overload to () operator (const version), allows access to i,j coordinate
* @param i - ith row
* @param j - jth column
* @return reference to the value stored in the i,j coordinate
*/
const float& operator()(int i, int j) const;
/**
* Overload to the [] operator, allows access and modification of the ith Matrix value as if
* it were flattened in to a vector.
* For example: Matrix M of shape (2,3) M[5] = M(1,2) (with column and row numbers starting from 0)
* @param i-ith coordinate of the flattened vector
* @return reference to the value in the ith coordinate
*/
float& operator[](int i);
/**
* Overload to the [] operator,(const version) allows access of the ith Matrix value as if
* it were flattened in to a vector.
* For example: Matrix M of shape (2,3) M[5] = M(1,2) (with column and row numbers starting from 0)
* @param i-ith coordinate of the flattened vector
* @return reference to the value in the ith coordinate
*/
const float& operator[](int i) const;
/**
* Image Prints the calling Matrix object
* @param os
* @return reference to the os
*/
friend std::ostream& operator<<(std::ostream &os, const Matrix& M);
/**
* Input of binary data to matrix
* @param is input stream to read from
* @param M matrix to fill
* @return ref to is
*/
friend std::istream& operator>>(std::istream &is, Matrix& M);
/**
* Scalar multiplication on the right of the matrix
* @param left
* @param right
* @return
*/
Matrix operator*(const float& right);
/**
* Scalar multiplication on the left of the matrix
* @param left
* @param right
* @return
*/
friend Matrix operator*(const float& left, const Matrix& right);
/***
* getter for the number of rows
*/
int getRows() const {return rows;}
/***
* getter for the number of columns
*/
int getCols() const {return cols;}
/**
* Transforms a matrix to a column vector.
* @return ref to this
*/
Matrix& vectorize() {
rows = rows * cols;
cols = 1;
return *this;
}
/**
* Plain prints this matrix, simply prints the elemnts space separated.
*/
void plainPrint(){
for(int i = 0; i < getRows(); i++){
for(int j = 0; j < getCols(); j++){
std::cout << (*this)(i,j) << " ";
}
std::cout << std::endl;
}
}
/**
* Plain prints this matrix, simply prints the elemnts space separated. const version
*/
void plainPrint() const{
for(int i = 0; i < getRows(); i++){
for(int j = 0; j < getCols(); j++){
std::cout << (*this)(i,j) << " ";
}
std::cout << std::endl;
}
}
private:
float *matrix;
int rows, cols;
};
This is being done as part of a C++ exercise in a course I'm a TA for. I'd like to try and find if my students passed their arguments as const references as we intended.
for example
using Traits = function_traits<decltype(&Matrix::operator=)>;
if(!std::is_same<const Matrix&, Traits::argument<1>::type>::value)
{
std::cerr << "Operator= does not accept by const reference" << std::endl;
exit(2);
}
This seems to work well for operators that aren't overloaded... However I can't get the same tests to work for operators that are overloaded such as * or the constructors.
This seems to be because decltype can't distinguish overloaded methods, however I've tried a couple of things for the past couple of hours and can't get anything to work.
Any suggestions?
Edit*
An example of something that won't work:
Thanks