How to avoid code duplication in this particular case - c++

I have these generic classes for 2D geometry:
template<class T> struct Point
{
T x,y;
//...Various member functions...
//T modulus() const noexcept { ... }
//T dist_from(const Point& other) const noexcept { ... }
//...
};
template<class T> class Polygon
{
public:
// ...An awful lot of member functions...
auto size() const noexcept { return vertexes.size(); }
//T area() const noexcept {...}
//T perimeter() const noexcept {...}
//T moment_of_inertia(const Point<T>&) const noexcept {...}
//void reorder_vertexes() {...}
//void transform(const Matrix& m) {...}
// ...
private:
std::vector<Point<T>> vertexes;
};
They work well and I use them in various part of the project. Now, for a particular application, I need Polygon but also need to associate some data to each of its vertexes.
Since Polygon vertexes can be transformed and reordered I would prefer to avoid the extra work of maintaining a parallel std::vector containing the additional data.
I would really like to introduce a new class like this:
template<class T, class D> class DecoratedPolygon
{
public:
struct DecoratedPoint
{
Point<T> point;
D data;
};
// Some specialized member functions...
const D& get_vertex_decoration(const std::size_t idx) const
{
return vertexes.at(idx).data;
}
// ...Then same member functions as polygon,
// except accessing the '.point'
auto size() const noexcept { return vertexes.size(); }
//...
private:
std::vector<DecoratedPoint> vertexes;
};
My problem whith this is that I don't want to rewrite a slightly modified version of all the member functions of Polygon.
How would you approach this particular case? I wonder if there is a zero cost technique to avoid that code duplication, or if simply I'm heading in the wrong way.

You could try to parameterize the Polygon class to take in the Point type as well:
template <class P> class Polygon {
std::vector<P> vertices
}
template <class T> class Point {
T x,y;
}
class DecoratedPoint : Point<long> {
int extraData;
}
Polygon<DecoratedPoint> newPoly;
The decorated data would end up coming from the point itself though, so the interface would look a bit different:
Polygon {
P get_point_at_idx( const std::size_t idx) {
return points.at(idx)
}
}
my_poly.get_point_at_idx(0).extraData
You'd need to change the implementation of Polygon a bit, but might provide more control longer term.

Related

Can you alias a method name in C++?

Consider I have some simple class:
template<typename T>
class Vector {
public:
T first() const { return this->m_first; }
T second() const { return this->m_second; }
private:
T m_first;
T m_second;
}
Now I want to create some meaning behind some of that:
typedef Vector<int> Position;
typedef Vector<unsigned int> Dimension;
Can I also create an alias to the methods of the new types Position and Dimension so that for Position, x() references frist(), y() references second() while for Dimension width() references first(), height() references second().
Or even more "speedy": Having first and second public, create aliases to the member variables? Real use case is more complex, but this should display what I want: Two things that are very similar in memory, but called completly different depending on the context.
You can achieve what you want by doing something like this:
class Position : private Vector<int> {
public:
auto x() const { return first(); }
auto y() const { return second(); }
};
class Dimension : private Vector<unsigned int> {
public:
auto width() const { return first(); }
auto height() const { return second(); }
};
which creates new types that inherit from a specific instantiation of Vector, and call the privately inherited member functions with publicly accessible meaningful names.
Here's a demo.

Hashing polymorphic type the proper way

I have a hash process implemented using Howard Hinnant's method (generic hash based on hash_append overloads).
The purpose of that method is to create hash of classes in order to "memoize" result of computations (see end of this answer), so I am facing some issue. In particular, consider the following possible Input class that needs to be hashed:
struct A {
virtual int do_stuff() const = 0;
virtual ~A();
};
struct B: A {
int do_stuff() const override { return 0; }
};
struct C: A {
const int u;
int do_stuff() const override { return u; }
};
struct Input {
A const& a; // store a reference to an instance of B or C
};
Now, if I want to hash Input, I will have something like:
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, Input const& input) {
hash_append(h, typeid(input));
hash_append(h, typeid(input.a));
}
So I need an overload of hash_append for A:
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, A const& a) {
hash_append(h, typeid(a));
}
The problem here is that depending on the runtime type of a, I would need to add extra information to the hash, e.g. for C I would need to add u.
I thought about the following solutions (and drawbacks):
add a virtual method to A that returns a specific value that can be added to the typeid() hash, but:
this means adding a method inside A that is not related to the purpose of A, thus I don't really like this idea (in particular because I have multiple A-like classes);
this breaks the concept of hash_append since the method will have a unique return type for all inheriting classes.
do a bunch of dynamic_cast inside hash_append:
I found this pretty ugly... in particular if I have multiple classes similar to A;
this is error-prone: if someone adds a new children of A and do not add a dynamic_cast inside hash_append.
Is there a way to hash a polymorphic type, without having to modify the type itself or rely on a bunch of dynamic_cast?
The final goal of this is to be able to memoize results of some heavy functions. Let's sketch the basic structure of my application:
struct Input { };
struct Result { };
Result solve(Input const&);
The solve function is computationally-heavy, so I want to save the results of previous computation in file using hash of Inputs, e.g. something like:
// depends on hash_append
std::string hash(Input const&);
Result load_or_solve(Input const& input) {
auto h = hash(input);
Result result;
if (exists(h)) { // if result exists, load it
result = load(h);
}
else { // otherwize, solve + store
result = solve(input);
store(h, result);
}
return result;
}
The load and store methods would load and store results from files, the goal is to memoize solutions between different runs.
If you have suggestion on how to memoize these results without having to deal with the above issues, I'll be glad to read them.
You can use double dispatching within the hash_append version of A and forward the request to the proper version (that is the one either for B or C). The drawback is that you must add boilerplate to those classes to accept a visitor and I cannot say if it's acceptable for you.
Here is a bunch of code that should illustrate the idea:
struct B;
struct C;
struct Visitor {
virtual void visit(const B &) = 0;
virtual void visit(const C &) = 0;
};
template<typename T, typename... O>
struct HashVisitor: T, HashVisitor<O...> {
template<typename U>
std::enable_if_t<std::is_same<T, U>::value> tryVisit(const U &u) {
T::operator()(u);
}
template<typename U>
std::enable_if_t<not std::is_same<T, U>::value> tryVisit(const U &u) {
HashVisitor<O...>::visit(u);
}
void visit(const B &b) override { tryVisit<B>(b); }
void visit(const C &c) override { tryVisit<C>(c); }
};
template<>
struct HashVisitor<>: Visitor {};
template<typename... F
auto factory(F&&... f) {
return HashVisitor<std::decay_t<F>>{std::forward<F>(f)...};
}
struct A {
virtual void accept(Visitor &) = 0;
virtual int do_stuff() const = 0;
virtual ~A();
};
struct B: A {
void accept(Visitor &v) override { v.visit(*this); }
int do_stuff() const override { return 0; }
};
struct C: A {
const int u;
void accept(Visitor &v) override { v.visit(*this); }
int do_stuff() const override { return u; }
};
template <class HashAlgorithm>
void hash_append(HashAlgorithm &, const B &) {
// do something
}
template <class HashAlgorithm>
void hash_append(HashAlgorithm &, const C &) {
// do something
}
template <class HashAlgorithm>
void hash_append(HashAlgorithm &h, const A &a) {
auto vis = factory(
[&h](const B &b){ hash_append(h, b); },
[&h](const C &c){ hash_append(h, c); }
);
a.accept(vis);
}

C++ compile time interpretation of sub-vectors and members

I have a particle class which keeps the position, velocity and the acceleration of an object. I can access the related part of the vector via .position(), .velocity() and .acceleration(). I also can access each single number like .velocity_x(), .velocity_y(), .velocity_z() etc. what I would like to do is to access the z part of velocity this way:
p.velocity().z()
I would like to use both .velocity() (as a subvector) and .velocity().z() (as a single number) at the same time.
I also would like to avoid defining any extra variable. I prefer everything be interpreted at the compile time (due to performance priority).
Is this implementation possible in c++?
In an attempt, I have considered returning another class with a functor. But beside the problem of compile time interpretation there is an issue with const as .velocity() does not know whether it will be followed by a const or non-const form of .z().
#include <iostream>
#include <armadillo>
class Particle
{
public:
arma::vec::fixed<9> data;
inline double velocity_z() const
{
return data(5);
}
inline double& velocity_z()
{
return data(5);
}
inline const arma::subview_col<double> position() const
{
return data.subvec(0,2);
}
inline arma::subview_col<double> position()
{
return data.subvec(0,2);
}
inline const arma::subview_col<double> velocity() const
{
return data.subvec(3,5);
}
inline arma::subview_col<double> velocity()
{
return data.subvec(3,5);
}
inline const arma::subview_col<double> acceleration() const
{
return data.subvec(6,8);
}
inline arma::subview_col<double> acceleration()
{
return data.subvec(6,8);
}
};
arma::vec vector3(double x,double y,double z)
{
return {x,y,z};
}
int main()
{
Particle p;
p.position()=vector3(1.1,2.1,3.1);
p.velocity()=vector3(1.2,2.2,3.2);
p.velocity_z()=10.0;
p.acceleration()=vector3(1.3,2.3,3.3);
p.data.print();
return 0;
}
// output:
// 1.1000
// 2.1000
// 3.1000
// 1.2000
// 2.2000
// 10.0000
// 1.3000
// 2.3000
// 3.3000
make:
g++ -std=c++11 test1.cpp -larmadillo
Armadillo documentation
Well, one possible solution would be to return a proxy object that both exposes the .{x|y|z}() member functions and is implicitly convertible to your vector type.
Conceptually like this:
#include <type_traits>
using vector_t = /* your library type */;
template<bool RValue>
class vector_proxy {
using return_type = typename std::conditional<RValue, vector_t&&, vector_t const&>::type;
vector_t &ref;
public:
vector_proxy(vector_t &ref) : ref(ref) {}
vector_proxy(vector_proxy const&) = delete;
vector_proxy& operator=(vector_proxy const&) = delete;
vector_proxy(vector_proxy&&) = delete;
vector_proxy& operator=(vector_proxy&&) = delete;
auto x() { /* code to produce x */ }
auto y() { /* code to produce y */ }
auto z() { /* code to produce z */ }
operator return_type() { return static_cast<return_type>(ref); }
};
Why a template? Because I would imagine you'd want different behavior, depending on the value category of the particle object.
We wouldn't want to return a non-const reference to a particles internal data if that particle is an lvalue. If it's an rvalue, we may as well return an rvalue reference as well so the code behaves "as expected".
The member function velocity() of the particle can have a value category qualifier to differentiate the two cases. And the template above just captures common behavior and abstracts the differences.
class particle {
// Members
public:
vector_proxy<false> velocity() const& { return {/* A ref to the velocity member */}; }
vector_proxy<true> velocity() && { return {/* A ref to the velocity member */}; }
// More functionality
};
Since you clarified in the comments that velocity always shuold returns a new vector object by value (an excellent default approach, btw), while allowing to modify the particle as well. The solution above needs to be updated:
class particle;
template<bool ByRef>
class vector_proxy {
using return_type =
typename std::conditional<ByRef, double&, double>::type;
using ref_type =
typename std::conditional<ByRef, particle&, particle const&>::type;
ref_type ref;
public:
vector_proxy(ref_type ref) : ref(ref) {}
vector_proxy(vector_proxy const&) = delete;
vector_proxy& operator=(vector_proxy const&) = delete;
vector_proxy(vector_proxy&&) = delete;
vector_proxy& operator=(vector_proxy&&) = delete;
return_type x();
return_type y();
return_type z();
operator vector_t();
};
class particle {
// Members
template<bool>
friend class vector_proxy;
public:
vector_proxy<false> velocity() const { return {*this}; }
vector_proxy<true> velocity() { return {*this}; }
// More functionality
};
template<bool ByRef>
auto vector_proxy<ByRef>::x -> return_type {
return ref.data(3);
}
template<bool ByRef>
auto vector_proxy<ByRef>::y -> return_type {
return ref.data(4);
}
template<bool ByRef>
auto vector_proxy<ByRef>::z -> return_type {
return ref.data(5);
}
template<bool ByRef>
vector_proxy<ByRef>::operator vector_t() {
return ref.data.subvec(3, 5)
}
And that should be it.

getting around const in an init method

So I can't use initializers in my class constructor because of using arrays, so I decided to use an init() method instead. Now I have a different problem. I have a class like this:
class EPWM {
private:
volatile EPWM_REGS* const regs;
public:
void init(volatile EPWM_REGS* _regs);
};
where I need to implement init() by initializing regs = _regs; but I can't because of the const. Is there a way to force the assignment in my init method? I would like to keep the const keyword so I don't accidentally reassign elsewhere.
edit: as much as I would like to use a constructor + initializer, which would solve this problem (my code used to do this), I cannot because I have another class which has an array of EPWM objects, and I can't initialize those objects because C++ does not support initializers for array members. (again, see the other question I asked a little while ago on this subject.)
Context for using EPWM is something like this:
class PwmGroup {
private:
EPWM *epwm;
void init(EPWM *_epwm) { epwm = _epwm; }
};
/* ... */
// main code:
EPWM epwm[3];
PwmGroup pwmGroup;
{
// EPwm1Regs, EPwm2Regs, EPwm3Regs are structs
// defined by TI's include files for this processor
epwm[0].init(&EPwm1Regs);
epwm[1].init(&EPwm2Regs);
epwm[2].init(&EPwm3Regs);
pwmGroup.init(epwm);
}
You could consider const_cast and pointers, but it's something best used very rarely. Something like...
EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(&regs);
*regsPP = _regs;
How about the following?
struct EPWM_array {
EPWM_array() { /* initialize array */ }
const EPWM *begin() const;
const EPWM *end() const;
EPWM array[ 10 ];
};
struct EPWMWrapper {
volatile EPWM_REGS* const regs;
EPWMWrapper(EPWM_array const& a) : regs(a.begin()) {}
};
Would something like this help? You can still intentionally violate the constness but it prevents normal people from silly mistakes (I haven't compiled this).
class EPWM {
private:
volatile EPWM_REGS* regs_for_init_never_use;
volatile EPWM_REGS* const& regs;
public:
EPWM() : regs(regs_for_init_never_use)
void init(volatile EPWM_REGS* _regs);
};
Playing devil's advocate: apart from the obvious documentation intent, since it's a private attribute, you could perfectly not use the const keyword and not modify it apart from the init method.
Your const_cast might actually be undefined behavior here, and I certainly prefer not to run in those dark corners, whatever the workarounds.
class EPWM {
private:
volatile EPWM_REGS* regs; // normally const, but need to be inited :/
public:
void init(volatile EPWM_REGS* _regs);
};
Although, revisit your question: while a raw array cannot be default constructed, you can write an array class that can be.
namespace detail
{
template <class T, size_t N, size_t index>
struct At
{
static T& Do(Array<T,N>& array)
{
return At<T,N-1,index-1>::Do(array.tail());
}
};
template <class T, size_t N>
struct At<T,N,0>
{
static T& Do(Array<T,N>& array) { return array[0]; }
};
template <class T, size_t index>
struct At<T,0,index> {};
template <class T>
struct At<T,0,0> {};
} // namespace detail
template <class T, size_t N>
class array
{
public:
typedef T value_type;
static const size_t Length = N;
array(): mHead(), mTail() {}
array(const array& rhs): mHead(rhs.mHead), mTail(rhs.mTail) {}
// Don't know whether it will be optimized or not
// Not sure I can use pointer arithmetic either :p
T& operator[](size_t index) { return index == 0 ? mHead : mTail[index-1]; }
// Compile time access
template <size_t index>
T& at() { return detail::At< T, N, index >::Do(*this); }
private:
T mHead;
array<T, N-1> mTail;
}; // class array<T,N>
template <class T>
class array<T,1>
{
public:
typedef T value_type;
static const size_t Length = 1;
array(): mHead() {}
array(const array& rhs): mHead(rhs.mHead) {}
T& operator[](size_t index) { return mHead; } // or error handling ;)
private:
T mHead;
}; // class array<T,1>
template <class T> class array<T,0> {}; // int[0] does not work (stack) so...
Okay... perhaps not as efficient as a real array... you can always turn to Preprocessor generation though:
template <class T>
class Array4
{
public:
Array4(): m0(), m1(), m2(), m3() {}
Array4(const Array4& rhs): m0(rhs.m0), m1(rhs.m1), m2(rhs.m2), m3(rhs.m3) {}
T& operator[](size_t index) { return *(&m0 + index); }
private:
T m0;
T m1;
T m2;
T m3;
}; // class Array4<T>
Use a constructor like this:
EPWM::EPWM(volatile EPWM_REGS* _regs)
: regs(_regs)
{}
Then simply have no params in init:
void EPWM::init()
{
// do something with this->regs here...
}
In other words, you can initialise everything in the class constructor - just not member arrays.

Generic object carrier class - C++

I need to create a generic object carrier class. I came up with something simple like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
This works well when T has got a default constructor (parameterless). Things gets complicated when T has parameterized constructors. So I rewrote the class like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return *item_;
}
void setItem(T& item)
{
item_ = new T ( item );
}
private:
T* item_;
};
Changed the item_ variable to T* and created a new instance using the copy constructor of T. Again this worked well until T is a pointer type. I mean ObjectCarrier<Foo*> won't work.
I am wondering how can I design this class so that it works for almost all kind of types. I think I may need to create a traits type specialized for pointers. But unfortunately, I am not able to make that work.
Any help would be great.
The above approaches are way way too complicated. Keep it simple, and just solve the constructor arg problem by using template constructors. Don't use pointers, they will create object lifetime and copying headaches.
Here's an implementation I use a lot. The template constructors will forward arguments for things directly on to the nested object which is convenient. The operator T& values let you pass carrier<T> to functions that take a type T, without expensive copying. You can wrap objects that take up to two arguments with this code.
/* A wrapper of type T */
template <typename T>
struct carrier {
carrier() {}
template <typename A1> carrier(const A1& a1) : value(a1) {}
template <typename A1, typename A2> carrier(const A1& a1, const A2& a2) : value(a1, a2) {}
operator T&() { return value; }
operator const T&() const { return value; }
T value;
};
You can use it like this:
const carrier<point> p1(10,10); // make p1 const to stop people changing it
showPoint(p1); // calls a function that expects a point,
showPoint(p1.value); // access the point directly
You can use template specialization for the T* type and rewrite the methods to suite pointers. You can do something like:
template<typename T>
class ObjectCarrier<T*>
{
public:
const T* item() const
{
return item_;
}
void setItem(T* item)
{
item_ = item;
}
private:
T* item_;
};
There is a design patern that is possibly relevant to this - Memento.
A bit off topic, but bear in mind that as soon as you start newing objects up inside your class, you'll need a way to manage the memory. I'd suggest using an std::auto_ptr at the least. You'll also need to provide a copy constructor and an assignment operator, when using std::auto_ptr.
It might be possible to hold the object by value and still defer its construction with the use of placement new and something like the following:
#include <iostream>
#include <cassert>
template <class T>
class ObjectCarrier
{
public:
ObjectCarrier(): ref(0) {}
ObjectCarrier(const ObjectCarrier& other): ref(0)
{
set_data(other.ref);
}
~ObjectCarrier()
{
clear();
}
const ObjectCarrier& operator = (const ObjectCarrier& other)
{
if (other.empty())
clear();
else
set_data(other.ref);
return *this;
}
void set(const T& value)
{
set_value(value);
}
const T& get() const
{
assert(!empty() && "No object being carried");
return *ref;
}
bool empty() const
{
return ref == 0;
}
void clear()
{
if (!empty()) {
ref->~T();
ref = 0;
}
}
private:
char data[sizeof(T)];
T* ref;
void set_value(const T& value)
{
if (!empty()) {
*ref = value;
}
else {
ref = new (data) T(value);
}
}
void set_data(const T* value)
{
if (value) {
set_value(*value);
}
}
};
int main()
{
ObjectCarrier<int> i;
ObjectCarrier<int> j(i);
i = j;
i.set(10);
std::cout << i.get() << '\n';
j = i;
i.set(20);
std::cout << i.get() << ' ' << j.get() << ' ' << ObjectCarrier<int>(i).get() << '\n';
}
However, I would somewhat question the usefulness of this class. Perhaps the only purpose it could have, would be to act as Boost.Optional.
But if you don't want the class to be able to not hold a value, just give it a parametrized constructor:
template<typename T>
class ObjectCarrier
{
public:
ObjectCarrier(const T& value = T()):
item_(value)
{
}
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
(It's just that this class seems rather useless, unless perhaps as a facade for code that expects variables to have item and setItem methods, rather than, say, an assignment operator.)
boost::optional does something very similar to this (also boost::any, but nevermind).
You can check out how its implemented at: http://cplusplus.co.il/2009/12/04/boost-optional-and-its-internals/ and don't worry - it's pretty straightforward.