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**>(®s);
*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.
Related
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.
If I have:
Class SomeClass{
private:
int a;
char* name;
public:
SomeClass(int a = 0, char* n = "---"){
...
}
};
Class OtherClass{
private:
SomeClass anArray[100];
int counter;
...
public:
...
};
How do I initialize the array of type SomeClass? As far as I know, when you have a private member that belongs to a user defined class, to initialize it you should include it in the constructor
OtherClass(...):SomeClass(...){
...
}
However, the contents of the array are left for the user to enter, so they are much too unpredictable, and manually entering default values for each field is obviously out of the question.
Given that your SomeClass has a default constructor, you don't need to anything: the default constructor will be call for each if the elements. You want to mention it explicitly can use
OtherClass::OtherClass()
: anArray() {
}
If you want to initialize the sequence of elements with an explicit constructor call with typing it out, you can use a delegating constructor taking a suitably size std::index_sequence<...> and use aggregate initialization of the elements. Here is a complete example of how that would look like:
#include <iterator>
#include <algorithm>
#include <iostream>
struct S {
int value;
S(int value): value(value) {}
};
std::ostream& operator<< (std::ostream& out, S const& s) {
return out << s.value;
}
template <typename S, typename T, std::size_t Size>
constexpr std::size_t static_size(T (S::*)[Size]) {
return Size;
}
class T {
S array[100];
template <std::size_t... I>
T(std::index_sequence<I...>): array{ S(I)... } {}
public:
T(): T(std::make_index_sequence<static_size(&T::array)>()) {}
S const* begin() const { return std::begin(array); }
S const* end() const { return std::end(array); }
};
int main()
{
T t;
std::copy(t.begin(), t.end(), std::ostream_iterator<S>(std::cout, " "));
}
I wanted to create a simple template class having a member variable ret. For some reason my MSVC 2010 compiler complains, that there is no declared variable named ret in Converter<double>. I'm really clueless, why?
template<typename M>
struct Converter {
M ret;
void operator()(const int& value) {
throw std::exception("Not implemented!");
}
};
template<>
struct Converter<double> {
void operator()(const int& value) {
ret=value;
}
};
int main() {
Converter<int> x;
}
This is another class (there is no inheritance or any other depenency here):
template<>
struct Converter<double> {
double ret;
void operator()(const int& value) {
ret=value;
}
};
I know this is already marked solved, but I thought I should just clarify this further.
Converter<double> and Converter<int> are different separate classes, so ret would not be defined in your double variation until you declare it as one of its members.
Regardless, it appears what you're trying to achieve is inheritance, which can be done in a similar way:
template<typename M>
struct AbstractConverter { // you could call it 'Converter' too, and it'll work as you expect
M ret;
virtual void operator()(const int& value) {
throw std::exception("Not implemented!");
}
//or
virtual void operator(const int &value) = 0; //pure virtual
// will not compile if someone wants to use it directly
};
template<>
struct Converter<double> : public AbstractConverter<double>{
void operator()(const int& value) { // we implement the operator here
ret=value;
}
};
I implemented the following smart pointer template class:
#ifndef __ProjectManager__mSharedPtr__
#define __ProjectManager__mSharedPtr__
#include <stdio.h>
#include "RefCount.h"
template <class T>
class mSmartPtr {
T *data;
RefCount *rc;
public:
mSmartPtr(T* srcPtr);
mSmartPtr(const mSmartPtr&);
~mSmartPtr();
T* operator->() const;
T& operator*() const;
mSmartPtr<T>& operator=( mSmartPtr&);
mSmartPtr<T> operator()(mSmartPtr&);
};
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator()(mSmartPtr<T>& src) {
return dynamic_cast<??>(src);
}
template <class T>
mSmartPtr<T>::mSmartPtr(T *srcPtr):
data(srcPtr) {
rc = new RefCount();
rc->add();
}
template<class T>
mSmartPtr<T>::~mSmartPtr() {
if (rc->remove() == 0) {
delete data;
delete rc;
}
}
template<class T>
mSmartPtr<T>::mSmartPtr(const mSmartPtr<T> &src):
data(src.data), rc(src.rc) {
rc->add();
}
template <class T>
T* mSmartPtr<T>::operator->() const {
return data;
}
template<class T>
T& mSmartPtr<T>::operator*() const {
return &data;
}
template <class T>
mSmartPtr<T>& mSmartPtr<T>::operator=( mSmartPtr<T> &src) {
if (this != &src) {
if (rc->remove() == 0) {
delete data;
delete rc;
}
data = src.data;
rc = src.rc;
rc->add();
}
return *this;
}
#endif /* defined(__ProjectManager__mSharedPtr__) */
let's say my application contains the following classes:
class Base
{
protected:
...
public:
virtual ~Base() =0;
...
};
class Derived1 : public Base
{
protected:
...
public:
virtual ~Derived1() {}
...
};
class Derived2 : public Base
{
protected:
...
public:
virtual ~Derived2() {}
...
};
and I need store data at the following way:
int int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Derived1> d1 = foo();
v.push_back(d1);
return 0;
}
I need to fix somehow the cast operator, but how? how do I get the base class in the dynamic cast?
#Guvante
Your code did not work , I modified it as follows but I don't know if will work well
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator ()(mSmartPtr<T>& src) {
mSmartPtr<T> retVal(dynamic_cast<T*>(src.data));
retVal.rc = src.rc;
retVal.rc.Add();
return retVal;
}
I think there is a better alternative to this. Unless you have a different location where you need to be able to do this, you can avoid the headache by changing the way you create the object.
int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Base> d1 = static_cast<Base*>(foo());
v.push_back(d1);
return 0;
}
Just avoid creating an mSmartPtr that is typed differently than your vector.
In your conversion method extract the underlying pointer and cast it then put it into the new smart pointer. Don't forget to copy the RefCount and ensure that your target class has a virtual destructor (so the correct one gets called no matter which smart pointer gets dispossed last).
I couldn't figure out how to define it externally but an inline definition worked.
//In the definition, replacing this line
//mSmartPtr<T> operator()(mSmartPtr&)
template<class Tdest>
operator mSmartPtr<Tdest>() {
mSmartPtr<Tdest> retVal(static_cast<Tdest*>(data));
retVal.rc = rc;
retVal.rc.Add();
return retVal;
}
In theory you could also add a version that takes a r-value if you are using C++11 but I think that would take a little work to do correctly so I avoided it.
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.