Explicit Object Member Functions (A.k.a Deducing this
)#
Problem: Repeated Code#
Typical problem: (non)``const`` getter overloads * ⟶ Repeated code
#include <vector>
#include <iostream>
class Matrix
{
public:
Matrix(unsigned xdim, unsigned ydim)
: _xdim(xdim), _ydim(ydim), _data(xdim*ydim) {}
const int& at(unsigned x, unsigned y) const
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return _data.at(y*_ydim + x); // <-- duplicate code
}
int& at(unsigned x, unsigned y)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return _data.at(y*_ydim + x); // <-- duplicate code
}
private:
unsigned _xdim, _ydim;
std::vector<int> _data;
};
int main()
{
Matrix m(2,2);
m.at(1,1) = 42;
std::cout << m.at(1,1) << std::endl; // <-- non-const at()
const Matrix& cm = m;
std::cout << cm.at(1,1) << std::endl; // <-- const at()
return 0;
}
Python Excursion: Explicit Object Parameter#
In Python, there is no implicit
this
According to Zen, Explicit is better than implicit (here)
Also, in Python, there is no overloading
Problem solved
(Assignment to
[]
expressions works differently in Python)
class Matrix:
def __init__(self, xdim, ydim):
self._xdim = xdim
self._ydim = ydim
self._data = [0 for _ in range(xdim*ydim)]
def at(self, x, y):
return self._data[y*self._ydim + x]
def set(self, x, y, value):
self._data[y*self._ydim + x] = value
m = Matrix(2,2)
m.set(1,1, 42)
print(m.at(1,1))
C++: Explicit Object Parameter (Since C++23)#
Really bad syntax
this
is only an annotation: “pass the object as (const) reference”⟶ No
const
method, butconst
object insteadStill duplicate code!
#include <vector>
#include <iostream>
class Matrix
{
public:
Matrix(unsigned xdim, unsigned ydim)
: _xdim(xdim), _ydim(ydim), _data(xdim*ydim) {}
const int& at(unsigned x, unsigned y) const
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return _data.at(y*_ydim + x); // <-- duplicate code
}
int& at(unsigned x, unsigned y)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return _data.at(y*_ydim + x); // <-- duplicate code
}
private:
unsigned _xdim, _ydim;
std::vector<int> _data;
};
int main()
{
Matrix m(2,2);
m.at(1,1) = 42;
std::cout << m.at(1,1) << std::endl; // <-- non-const at()
const Matrix& cm = m;
std::cout << cm.at(1,1) << std::endl; // <-- const at()
return 0;
}
Template Method To Deduplicate#
Return type deduction
Deduced from selected
vector::at()
method
#include <vector>
#include <iostream>
class Matrix
{
public:
Matrix(unsigned xdim, unsigned ydim)
: _xdim(xdim), _ydim(ydim), _data(xdim*ydim) {}
template <typename Self>
auto& at(this Self& self, unsigned x, unsigned y)
{
return self._data.at(y*self._ydim + x);
}
private:
unsigned _xdim, _ydim;
std::vector<int> _data;
};
int main()
{
Matrix m(2,2);
m.at(1,1) = 42;
std::cout << m.at(1,1) << std::endl;
const Matrix& cm = m;
std::cout << cm.at(1,1) << std::endl;
return 0;
}
Even Shorter: Abbreviated Function Template#
Cool
Readable?
#include <vector>
#include <iostream>
class Matrix
{
public:
Matrix(unsigned xdim, unsigned ydim)
: _xdim(xdim), _ydim(ydim), _data(xdim*ydim) {}
auto& at(this auto& self, unsigned x, unsigned y)
{
return self._data.at(y*self._ydim + x);
}
private:
unsigned _xdim, _ydim;
std::vector<int> _data;
};
int main()
{
Matrix m(2,2);
m.at(1,1) = 42;
std::cout << m.at(1,1) << std::endl;
const Matrix& cm = m;
std::cout << cm.at(1,1) << std::endl;
return 0;
}