I just found something that looks like a quirk to me. Consider :
struct Tile {
Tile(Map &map, int, int)
: map(map) { }
void destroy();
void display() const;
Map ↦
};
This (stripped down) class is an accessor object. It's constructed by the Map itself as such :
Tile Map::operator ()(int x, int y) {
return Tile(*this, x, y);
}
Tile const Map::operator ()(int x, int y) const {
return Tile(*this, x, y);
}
So a Map can return a Tile from which we can call destroy() (which updates the map), and a Map const can only return a Tile const, from which we can only call the non-modifying display() method.
So everything's good, right ? Well, not quite. Because even though it seemed pretty straightforward at first, I can't figure out how to construct a Tile from a Map const, because of the Map& constructor parameter.
I also tried removing Tile's constructor and aggregate-initializing it, to no avail :
Tile const Map::operator ()(int x, int y) const {
return { *this, x, y };
}
... which looks even stranger to me, since I get an...
error: invalid initialization of reference of type ‘Map&’ from expression of type ‘const Map’
... even though a Tile const should only contain const fields, shouldn't it ?
Why does the compiler complain on that last one (the first is quite logical), and can I do something short of rewriting the whole Tile class specifically for const access ? Could it be one of the mythical places where const_cast is right ?
Thanks in advance.
Daniel's on the right track - you definitely need a Tile and ConstTile class, which can be templated for simplicity, but you need to deal with when you can call destroy() and how you can construct them. To that end:
template<class MapT>
struct TileT {
TileT(MapT &map, int, int)
: map(map) { }
// we want to be able to construct ConstTile from Tile
template <typename M>
TileT(const TileT<M>& tile)
: map(tile.map) { }
void destroy() {
static_assert(!std::is_const<MapT>::value, "Cannot call destory() from ConstTile");
// rest of implementation
}
void display() const;
MapT ↦
};
using Tile = TileT<Map>;
using ConstTile = TileT<const Map>;
That will give you the desired functionality and will work in a similar fashion to how iterator/const_iterator work. So you can do stuff like:
Map map;
...
ConstTile tile = map(4,3); // non-const map, ConstTile is ok
I see no way around creating two versions of the Tile class: One for const access and one for mutable access. Consider the following: What should the destroy function do, if the Map reference is const?
If you want to get around making a Tile and a ConstTile version of the class, you can use templates to achieve the same effect and still avoid code duplication.
template<class MapT>
struct Tile {
Tile(MapT &map, int, int)
: map(map) { }
template<typename U = MapT>
std::enable_if<std::is_const<U>::value> destroy();
void display() const;
MapT ↦
};
MapT can now be Map or const Map depending on the instantiation.
Related
Let's say I have a class which implements any number of similar methods, same return type and same parameter type to keep it simple.
Header:
protected:
void MoveForward(float Magnitude);
void MoveRight(float Magnitude);
Implementation:
void MyCharacter::MoveForward(float Magnitude) {
AddMovementInput(GetActorForwardVector() * Magnitude);
}
void Myharacter::MoveRight(float Magnitude) {
AddMovementInput(GetActorRightVector() * Magnitude);
}
Very similar methods, but only differing by the direction (Forward and Right in this case) in the method name, and the name of one of the internal functions.
What is the best way to abstract the common generic structure here?
You can do it in multiple ways, personally I've used an approach similar to the following:
enum class Direction { LEFT, RIGHT, TOP, BOTTOM };
class MyCharacter {
template<Direction DIR> Vector MyCharacter::getVector() const;
template<Direction DIR> void move() {
AddMovementInput(getVector<Dir>() * magnitude);
}
}
template<> Vector MyCharacter::getVector<Direction::LEFT>() const { ... }
template<> Vector MyCharacter::getVector<Direction::RIGHT>() const { ... }
Of course you can do the same exact thing without templates but I guess that you know what you are doing if you are specifically needing them.
Mind that you could directly pass the function as a template argument but I found it less clear, something like:
float GetActorForwardVector() { return 3.0f; }
class Foo
{
public:
template<float (*F)()> float move() { return F(); }
inline float moveLeft() { return move<GetActorForwardVector>(); }
};
int main()
{
Foo foo;
std::cout << foo.moveLeft();
}
To be honest you should not generalize at this level of algorithm. You just get a vector and scale it with a constant. If you were doing something more complex, then it would be another story. My first and foremost suggestion is let it stay this way.
Second, if you insist on generalization here it is (I assume GetXVector methods are class member):
class Foo
{
protected:
void MoveForward(float x) { Move(&Foo::GetActorForwardVector, x); }
void MoveRight(float x) { Move(&Foo::GetActorRightVector, x); }
private:
template<typename GetDirectionFunc>
void Move(GetDirectionFunc getDirection, float x)
{
AddMovementInput((this->*getDirection)() * x);
}
};
I prefer your original code.
You could use tag-dispatching.
Create the tag classes with same static member functions which implement the specific behavior:
namespace Direction {
struct Forward
{
static Vector actorVector() { return GetActorForwardVector(); }
};
struct Right
{
static Vector actorVector() { return GetActorRightVector(); }
};
} // namespace Direction
In your class, implement a template move function which takes an instance of the Direction class, but doesn't use it. Instead it calls the static member function of the tag class.
class MyCharacter
{
public:
template< typename Direction >
void move( const float magnitude, const Direction )
{
AddMovementInput( Direction::actorVector() * magnitude );
}
};
Usage example:
MyCharacter mc;
mc.move( 10.0, Direction::Forward() );
If you want to create more directions, only a new tag class is needed which implements the static member function.
Templates are not meant to be used when you handle different values (forward, right), they meant to handle different types (int, double).
You can use one generic Move function with arguments:
void Move(int x, int y);
// Move forward
Move (0, 1);
// Move right
Move (1, 0);
You can use function pointers to combine move direction and corresponding function in a struct:
struct MOVE_INFO
{
int x;
int y;
void (*GetVector)(void);
}
void Move(MOVE_INFO mv)
{
...
mv.GetVector();
...
}
main()
{
MOVE_INFO forward = {0, 1, SomeLib::GetForwardVector};
MOVE_INFO right = {1, 0, SomeLib::GetRightVector};
// Move Forward
Move(forward);
// Move Right
Move(right);
}
I'm having a custom structure called SortedArrayList<T> which sorts its elements according to a comparator, and I would like to prevent assigning using operator[].
Example:
ArrayList.h
template <typename T> class ArrayList : public List<T> {
virtual T& operator[](const int& index) override; //override List<T>
virtual const T operator[](const int& index) const override; //override List<T>
}
SortedLinkedList.h with following operators
template <typename T> class SortedArrayList : public ArrayList<T> {
public:
SortedArrayList<T>(const std::function<bool(const T&, const T&)>& comparator);
T& operator[](const int& index) override; //get reference (LHS)
const T operator[](const int& index) const override; //get copy (RHS)
}
Test.h
ArrayList<int>* regular = new ArrayList<int>();
ArrayList<int>* sorted = new SortedArrayList<int>(cmpfn);
(*regular)[0] == 5; //allow
(*regular)[0] = 5; //allow
(*sorted)[0] == 7; //allow
(*sorted)[0] = 7; //except
Is this operation possible?
By prevent I mean throwing an exception or something what will warn user to not do it.
Prefer aggregation over inheritance:
template <typename T> class SortedArrayList {
ArrayList<T> m_the_list;
public:
SortedArrayList<T>(const std::function<bool(const T&, const T&)>& comparator);
const T& operator[](const int& index) const {return m_the_list[index];}; // always get const reference
// Can act as a *const* ArrayList<T>, but not as a mutable ArrayList<T>, as that would violate Liskov's substitution principle.
operator const ArrayList<T>&() const {return m_the_list;}
}
As Stephen Newell correctly points out, when you're using inheritance, you're guaranteeing your class SortedArrayList can act as an ArrayList in every possible scenario. This is clearly not the case in your example.
You can read more here about how violating Liskov's Substitution Principle is a bad idea.
You should not do this. It indicates an improper design See the C++ FAQ on Inheritance. Your subclass doesn't fulfill the "is-a" requirement for public inheritance if it can't be used in all ways as the base class (LSP).
If you want to have one type of container that allows member replacement and another that doesn't, then the define the base class that just allows const member access (no need to make it virtual). Then branch from there to MutableList and ImmutableList, and let SortedArrayList derive from Immutable list.
Seems to me like the best practice here would be to implement an at(const int& index) method instead of overloading []. That would be more clear to the user of the interface anyway.
There is a similar function in std::map and other std data structures. For example: http://www.cplusplus.com/reference/map/map/at/
Why do you pass the index as reference at all? Absolutely no need for...
I personally recommend to use unsigned integer types for array indices (what would be the meaning of a negative index anyway???).
const for a type returned by value is (nearly) meaningless - it will be copied to another variable anyway (which then will be modifiable), but you prevent move semantics...
So:
T& operator[](unsigned int index); //get reference (LHS)
T operator[](unsigned int index) const; //get copy (RHS)
(Just some improvement suggestions...)
Now to the actual question: Disallowing modification is quite easy:
//T& operator[](unsigned int index); //get reference (LHS)
T const& operator[](unsigned int index) const; //get copy (RHS)
Just one single index operator, always returning const reference... If user can live with reference, fine, otherwise he/she will copy the value anyway...
Edit in adaption to modified question:
As now inheritance is involved, the stuff gets more complicated. You cannot just get rid of some inherited function, and the inherited one will allow element modification.
In the given situation, I'd consider a redesign (if possible):
class ArrayListBase
{
public:
T const& operator[](unsigned int index) const;
// either copy or const reference, whichever appears more appropriate to you...
};
class ArrayList : public ArrayListBase
{
public:
using ArrayListBase::operator[];
T& operator[](unsigned int index);
}
class SortedArrayList : public ArrayListBase
{
public:
// well, simply does not add an overload...
}
The insertion function(s) might be pure virtual in the base class (where a a common interface appears suitable) or only available in the derived classes. Decide you...
I'm working on a 2D game engine and I continuosly run into template problems. So, for this one, I've got a templated function like this:
template <class T>
T *S2M_CreateObject(int x, int y) {
return new T(x, y);
}
now, I would like the game to load the level data from a file, and that includes loading and instantiating Object-derived classes, so I made an std::map like this:
map <string, Object *(*)(int x, int y)> o {
{ "warp", &S2M_CreateObject<Warp> }
};
which stores a string that I will be using in the level editor to refer a determined class and maps it to a function pointer that would create an instance of that said class.
I hope you get the idea, this is the approach I like the most but it is not working. However, it works if I delete the Warp template specifier (Warp is a derived class of Object), but that is not the goal. I know I could create a function for every object type I have defined in the game, but since I'm programming a game engine, I can't figure out how many Object-derived classes the user will create and I cannot expect him/her to program each function.
Any other way I can do this?
Whereas Warp* can be implicitly converted to Object*, a pointer to a function returning Warp* cannot be implicitly converted to a pointer to a function returning Object*. Nor, in general, can such a conversion be performed safely at all.
Now the reason why your code doesn't work should be clear. &S2M_CreateObject<Warp> has type Warp* (*)(int, int), and this can't be implicitly converted to Object* (*)(int, int). Instead, you can make the S2M_CreateObject function always return Object* regardless of which type is actually created:
#include <map>
#include <string>
using namespace std;
struct Object {
Object() {}
Object(int x, int y) {}
};
struct Warp : Object {
Warp() {}
Warp(int x, int y) {}
};
template <class T>
Object* S2M_CreateObject(int x, int y) {
return new T(x, y);
}
int main() {
map<string, Object *(*)(int x, int y)> o {
{ "warp", &S2M_CreateObject<Warp> }
};
}
Thanks to your previous help, I could do something like this: here is somehow the working result (simplified). I used it with a quite simple range function
//Define your template function
template<typename Type>
void fnRangeValue(CMyClass * poMyObject, std::string strFormat){
Type tMyField, tMinValue, tMaxValue;
/*Do what you have to here!*/
}
//Define a macro for your pointerFunction
typedef void (*fnPointerFunctionRange)(CMyClass * poMyObject, std::string strFormat );
// Define your lookup table (map)
const std::map<std::string, fnPointerFunctionRange> ST_FORMAT_RANGE_POINTER= {
{"UINT8",&fnRangeValue<uint8_t>},
{"STR1UINT8",&fnRangeValue<uint8_t>},
{"UINT16",&fnRangeValue<uint16_t>},
{"STR2UINT16",&fnRangeValue<uint16_t>},
{"STR4UINT16",&fnRangeValue<uint16_t>},
{"UINT32",&fnRangeValue<uint32_t>},
{"INT8",&fnRangeValue<int8_t>},
{"INT16",&fnRangeValue<int16_t>},
{"STR3INT16",&fnRangeValue<int16_t>},
{"INT32",&fnRangeValue<int32_t>},
{"FLT32",&fnRangeValue<float>},
{"FLT64",&fnRangeValue<double>},
{"STR7FL64",&fnRangeValue<double>},
{"STR8FL64",&fnRangeValue<double>},
};
void fnRangeField(CMyClass * poMyObject){
std::string strFormat;
fnPointerFunctionRange poFonctionRange;
strFormat = "UINT8";
auto itMapRangePointer = ST_EOIIM_FORMAT_RANGE_POINTER.find(strFormat);
if(itMapRangePointer != ST_FORMAT_RANGE_POINTER.end()){
poFonctionRange = ST_FORMAT_RANGE_POINTER.at(strFormat);
// Call of the right template function thanks to pointers
poFonctionRange(poMyObject,strFormat);
}
}
Hope it will help you!
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () const {
return &(Enum::OfInt(i)); // warning: taking address of temporary
}
const Enum operator* () const {
return Enum::OfInt(i); // There is no problem with this one!
}
private:
int i;
};
I get this warning above. Currently I'm using this hack:
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
private:
int i;
Enum tmp;
};
But this is ugly because iterator serves as a missing container.
What is the proper way to iterate over range of values?
Update:
The iterator is specialized to a particular set objects which support named static constructor OfInt (code snippet updated).
Please do not nit-pick about the code I pasted, but just ask for clarification. I tried to extract a simple piece.
If you want to know T will be strong enum type (essentially an int packed into a class). There will be typedef EnumIterator < EnumX > Iterator; inside class EnumX.
Update 2:
consts added to indicate that members of strong enum class that will be accessed through -> do not change the returned temporary enum.
Updated the code with operator* which gives no problem.
Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
The problem with this isn't that it's ugly, but that its not safe. What happens, for example in code like the following:
void f(EnumIterator it)
{
g(*it, *it);
}
Now g() ends up with two pointers, both of which point to the same internal temporary that was supposed to be an implementation detail of your iterator. If g() writes through one pointer, the other value changes, too. Ouch.
Your problem is, that this function is supposed to return a pointer, but you have no object to point to. No matter what, you will have to fix this.
I see two possibilities:
Since this thing seems to wrap an enum, and enumeration types have no members, that operator-> is useless anyway (it won't be instantiated unless called, and it cannot be called as this would result in a compile-time error) and can safely be omitted.
Store an object of the right type (something like Enum::enum_type) inside the iterator, and cast it to/from int only if you want to perform integer-like operations (e.g., increment) on it.
There are many kind of iterators.
On a vector for example, iterators are usually plain pointers:
template <class T>
class Iterator
{
public:
T* operator->() { return m_pointer; }
private:
T* m_pointer;
};
But this works because a vector is just an array, in fact.
On a doubly-linked list, it would be different, the list would be composed of nodes.
template <class T>
struct Node
{
Node* m_prev;
Node* m_next;
T m_value;
};
template <class T>
class Iterator
{
public:
T* operator->() { return m_node->m_value; }
private:
Node<T>* m_node;
};
Usually, you want you iterator to be as light as possible, because they are passed around by value, so a pointer into the underlying container makes sense.
You might want to add extra debugging capabilities:
possibility to invalidate the iterator
range checking possibility
container checking (ie, checking when comparing 2 iterators that they refer to the same container to begin with)
But those are niceties, and to begin with, this is a bit more complicated.
Note also Boost.Iterator which helps with the boiler-plate code.
EDIT: (update 1 and 2 grouped)
In your case, it's fine if your iterator is just an int, you don't need more. In fact for you strong enum you don't even need an iterator, you just need operator++ and operator-- :)
The point of having a reference to the container is usually to implement those ++ and -- operators. But from your element, just having an int (assuming it's large enough), and a way to get to the previous and next values is sufficient.
It would be easier though, if you had a static vector then you could simply reuse a vector iterator.
An iterator iterates on a specific container. The implementation depends on what kind of container it is. The pointer you return should point to a member of that container. You don't need to copy it, but you do need to keep track of what container you're iterating on, and where you're at (e.g. index for a vector) presumably initialized in the iterator's constructor. Or just use the STL.
What does OfInt return? It appears to be returning the wrong type in this case. It should be returning a T* instead it seems to be returning a T by value which you are then taking the address of. This may produce incorrect behavior since it will loose any update made through ->.
As there is no container I settled on merging iterator into my strong Enum.
I init raw int to -1 to support empty enums (limit == 0) and be able to use regular for loop with TryInc.
Here is the code:
template <uint limit>
class Enum {
public:
static const uint kLimit = limit;
Enum () : raw (-1) {
}
bool TryInc () {
if (raw+1 < kLimit) {
raw += 1;
return true;
}
return false;
}
uint GetRaw() const {
return raw;
}
void SetRaw (uint raw) {
this->raw = raw;
}
static Enum OfRaw (uint raw) {
return Enum (raw);
}
bool operator == (const Enum& other) const {
return this->raw == other.raw;
}
bool operator != (const Enum& other) const {
return this->raw != other.raw;
}
protected:
explicit Enum (uint raw) : raw (raw) {
}
private:
uint raw;
};
The usage:
class Color : public Enum <10> {
public:
static const Color red;
// constructors should be automatically forwarded ...
Color () : Enum<10> () {
}
private:
Color (uint raw) : Enum<10> (raw) {
}
};
const Color Color::red = Color(0);
int main() {
Color red = Color::red;
for (Color c; c.TryInc();) {
std::cout << c.GetRaw() << std::endl;
}
}
Edit1: I realize this is hard to understand this question without having an insight of what I'm trying to do. The class A is not complete but it essentially stand for a C-array "proxy" (or "viewer" or "sampler"). One interesting usage is too present a C-array as a 2d grid (the relevant function are not shown here). The property of this class are the following:
it should not own the data - no deep copyy
it should be copyable/assignable
it should be lightweight (
it should preserve constness (I'm having trouble with this one)
Please do not question the purpose or the design: they are the hypothesis of the question.
First some code:
class A
{
private:
float* m_pt;
public:
A(float* pt)
:m_pt(pt)
{}
const float* get() const
{
return m_pt;
}
void set(float pt)
{
*m_pt = pt;
}
};
void gfi()
{
float value = 1.0f;
const A ac(&value);
std::cout<<(*ac.get())<<std::endl;
A a = ac;
a.set(2.0f);
std::cout<<(*ac.get())<<std::endl;
}
Calling "gfi" generate the following output:
1
2
Assigning a with ac is a cheap way to shortcut the constness of ac.
Is there a better way to protect the value which m_pt point at?
Note that I DO want my class to be copyable/assignable, I just don't want it to loose its constness in the process.
Edit0: I also DO want to have a pointer in there, and no deep copy please (let say the pointer can be a gigantic array).
Edit2: thanks to the answers, I came to the conclusion that a "const constructor" would be a useful thing to have (at least in this context). I looked it up and of course I'm not the same one who reached this conclusion. Here's an interesting discussion:
http://www.rhinocerus.net/forum/language-c-moderated/569757-const-constructor.html
Edit3: Finally got something which I'm happy with. Thanks for your help. Further feedback is more than welcome
template<typename T>
class proxy
{
public:
typedef T elem_t;
typedef typename boost::remove_const<T>::type elem_unconst_t;
typedef typename boost::add_const<T>::type elem_const_t;
public:
elem_t* m_data;
public:
proxy(elem_t* data = 0)
:m_data(data)
{}
operator proxy<elem_const_t>()
{
return proxy<elem_const_t>(m_data);
}
}; // end of class proxy
void test()
{
int i = 3;
proxy<int> a(&i);
proxy<int> b(&i);
proxy<const int> ac(&i);
proxy<const int> bc(&i);
proxy<const int> cc = a;
a=b;
ac=bc;
ac=a;
//a=ac; // error C2679: binary '=' : no operator found which takes a right-hand operand of type...
//ac.m_data[0]=2; // error C3892: 'ac' : you cannot assign to a variable that is const
a.m_data[0]=2;
}
Your class is badly designed:
it should use float values, not pointers
if you want to use pointers, you probably need to allocate them dynamically
and then you need to give your class a copy constructor and assignment operator (and a destructor) , which will solve the problem
Alternatively, you should prevent copying and assignment by making the copy constructor and assignment op private and then not implementing them.
You can trick around with proxy pattern and additional run-time constness boolean member. But first, please tell us why.
Effectively your class is like an iterator that can only see one value. It does not encapsulate your data just points to it.
The problem you are facing has been solved for iterators you should read some documentation on creating your own iterator and const_iterator pairs to see how to do this.
Note: in general a const iterator is an iterator that cannot be incremented/decremented but can change the value it points to. Where as a const_iterator is a different class that can be incremented/decremented but the value it points to cannot be changed.
This is the same as the difference between const float * and float *const. In your case A is the same as float * and const A is the same as float *const.
To me your choices seem to be:
Encapsulate your data.
Create a separate const_A class like iterators do
Create your own copy constructor that does not allow copies of const A eg with a signature of A(A & a);
EDIT: considering this question some more, I think you are misinterpreting the effect of const-correctness on member pointers. Consider the following surprising example:
//--------------------------------------------------------------------------------
class CNotSoConstPointer
{
float *mp_value;
public:
CNotSoConstPointer(float *ip_value) : mp_value(ip_value) {}
void ModifyWithConst(float i_value) const
{
mp_value[0] = i_value;
}
float GetValue() const
{
return mp_value[0];
}
};
//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
float value = 12;
const CNotSoConstPointer b(&value);
std::cout << b.GetValue() << std::endl;
b.ModifyWithConst(15);
std::cout << b.GetValue() << std::endl;
while(!_kbhit()) {}
return 0;
}
This will output 12 and then 15, without ever being "clever" about the const-correctness of the const not-so-const object. The reason is that only the pointer ITSELF is const, not the memory it points to.
If the latter is what you want, you'll need a lot more wrapping to get the behavior you want, like in my original suggestion below or Iain suggestion.
ORIGINAL ANSWER:
You could create a template for your array-proxy, specialized on const-arrays for the const version. The specialized version would have a const *m_pt, return a const pointer, throw an error when you try to set, and so on.
Edit: Something like this:
template<typename T>
class TProxy
{
T m_value;
public:
TProxy(T i_t) : m_value(i_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.m_value) {}
T get() { return m_value; }
void set(T i_t) { m_value = i_t; }
};
template<typename T>
class TProxy<const T *>
{
const T *mp_value;
public:
TProxy(const T *ip_t) : mp_value(ip_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.mp_value) {}
T get() { return m_value; }
};
Why not replace float* with float in A. If you don't either the original owner of the float that the float* references can change it, or anyone prepared to do a mutable cast on the return value from a::get.
const is always just a hint to the compiler; there are no ways to make a variable permanently read-only.
I think you should use deep copy and define your own assingment operator and copy constructor.
Also to return handle to internal data structure in not a good practice.
You can deny the copy-constructor for certain combinations of arguments:
For instance, adding the constructor;
A(A& a) :m_pt(a.m_pt) { m_pt = a.m_pt; }
prevents any instance of A being initialised with a const A.
This also prevents const A a2 = a1 where a1 is const, but you should never need to do this anyway, since you can just use a1 directly - it's const even if you could make a copy, a2 would be forever identical to a1.