Just as the title asks, does C++ have the equivalent of Python's setitem and getitem for classes?
Basically it allows you to do something like the following.
MyClass anObject;
anObject[0] = 1;
anObject[1] = "foo";
basically, you overload the subscript operator (operator[]), and it returns a reference (so it can be read as well as written to)
You can overload the [] operator, but it's not quite the same as a separate getitem/setitem method pair, in that you don't get to specify different handling for getting and setting.
But you can get close by returning a temporary object that overrides the assignment operator.
To expand on Earwicker post:
#include <string>
#include <iostream>
template <typename Type>
class Vector
{
public:
template <typename Element>
class ReferenceWrapper
{
public:
explicit ReferenceWrapper(Element& elem)
: elem_(elem)
{
}
// Similar to Python's __getitem__.
operator const Type&() const
{
return elem_;
}
// Similar to Python's __setitem__.
ReferenceWrapper& operator=(const Type& rhs)
{
elem_ = rhs;
return *this;
}
// Helper when Type is defined in another namespace.
friend std::ostream& operator<<(std::ostream& os, const ReferenceWrapper& rhs)
{
return os << rhs.operator const Type&();
}
private:
Element& elem_;
};
explicit Vector(size_t sz)
: vec_(sz)
{
}
ReferenceWrapper<const Type> operator[](size_t ix) const
{
return ReferenceWrapper<const Type>(vec_[ix]);
}
ReferenceWrapper<Type> operator[](size_t ix)
{
return ReferenceWrapper<Type>(vec_[ix]);
}
private:
std::vector<Type> vec_;
};
int main()
{
Vector<std::string> v(10);
std::cout << v[5] << "\n";
v[5] = "42";
std::cout << v[5] << "\n";
}
It's not portable, but MSVC has __declspec(property), which also allows indexers:
struct Foo
{
void SetFoo(int index, int value) { ... }
int GetFoo(int index) { ... }
__declspec(property(propget=GetFoo, propput=SetFoo)) int Foo[];
}
other than that, Earwicker did outline the portable solution, but he's right that you'll run into many problems.
Related
as you can see from the code I want to overload the < operator twice. 1 to sort by dist and the other by nodeID. I would like to check if there is any way to call the different overloaded methods. For example in the compLoc method, when I use the sort() method I want it to be sorted by nodeID but in other methods I want it to be sorted by dist.
struct AttSet{
int nodeID;
double dist;
bool operator < (const AttSet & str) const{
return (dist < str.dist);
}
/*
bool operator <(const AttSet & str){
return (nodeID < str.nodeID);
*/
bool operator == (const AttSet & str){
return nodeID == str.nodeID;
}};
void compLoc(Edge *edge, vector<Node*> &vertices){
int l = edge->length;
int vl = edge->head->nodeID;
int vr = edge->tail->nodeID;
/*
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end());
sort(vertices[vr]->attSet.begin(), vertices[vr]->attSet.end());
vector<AttSet> vInterSec;
set_intersection(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), vertices[vr]->attSet.begin(), vertices[vr]->attSet.end(), back_inserter(vInterSec));
*/}
You cannot have overloads that have the same signature. This holds for any function. How would you try to decide which version to use?
If you want sort the object based on different criteria you should use the sort version that takes a custom comparer function as the third argument.
Edit:
Of course you need to provide the comparer. I would suggest providing the comparers as static functions of the class if you have such power. This way you will not pollute enclosing namespace and you can access privates of the class with out exposing any getters. Since your properties are public the lambda would suffice, and probably be the best/cleanest approach.
Feeling adventurous I made a simple c++11 exercise program. For what it's worth, if you ever decided to go for proper encapsulation, I've shown both approaches:
#include <iostream>
#include <algorithm>
#include <vector>
#include <initializer_list>
#include <cassert>
using namespace std;
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v){
for(const auto& el : v){
out << el << '\n';
}
return out;
}
class A {
int a;
int b;
public:
A(std::initializer_list<int> l){
assert(l.size() == 2);
auto i = l.begin();
a = *i;
++i;
b = *i;
}
friend std::ostream& operator<<(std::ostream& stream, const A& e){
return stream << e.a << ' ' << e.b;
}
static bool compareViaA(const A& lhs, const A& rhs){
return rhs.a > lhs.a;
}
static bool compareViaB(const A& lhs, const A& rhs){
return rhs.b > lhs.b;
}
};
int main() {
std::vector<A> v {{2,3}, {3,2}, {1,4}, {4,1}};
//sort(v.begin(), v.end(), [](const A& a, const A& b){return a.a > b.a;}) // fails because of privacy violation
sort(v.begin(), v.end(), A::compareViaA);
std::cout << v << '\n';
sort(v.begin(), v.end(), A::compareViaB);
std::cout << v << '\n';
return 0;
}
Live: http://ideone.com/lDMujx.
I think you can implement this by using functor and take the comparator(operator< overload) outside the AttSet.
Here is a simple example:
struct AtrComparator {
bool distcmp;
AttrComparator(bool distcmp): distcmp(distcmp) {}
bool operator() (const AttSet &s1, const AttSet &s2) {
if(distcmp) {
return s1.dist < s2.dist;
} else {
return s1.nodeID < s2.nodeID;
}
}
}
And then you can do the sort through different feed, dist or nodeID.
.e.g:
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(true));
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(false));
You can't do that. They have the same signature exactly.
Use a functor or a lambda and pass it to whatever algorithm you want.
std::sort(std::begin(container), std::end(container),
[](const element_type& lhs, const element_type& rhs) { return ...; });
Another way to do this:
struct compare_by_node_id {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.nodeID < rhs.nodeID;
}
};
struct compare_by_dist {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.dist < rhs.dist;
}
};
And you could pass that to the algorithm like:
std::sort(std::begin(container), std::end(container), compare_by_node_id());
you cannot do that because compiler doesn't see difference between:
bool operator < (const AttSet & str) const; //this const doesn't allow to override any property of object(instance of AttSet) if I remember
and
bool operator < (const AttSet & str);
there're the same same return type, same parameter (same signature)
compiler cannot choose which one is better
There's not a great way to do this as far as I am aware, since the compiler will see these as the exact same and will throw an error. If you need to do this, use the < operator as whatever will occur the most often, and then write a method that you can call to compare two object. Something like this:
bool operator< (const Blah &blah) const {
return (most often operation)
}
bool Blah::other_operation(const Blah &blah) const {
return (other operation)
}
this is my first question on the site.
A little problem met me today. I can't call a global function Swap within a assignment operator and move constructor from the DynamicArray template class. When I try to do this I get an error C2660 saying:
'DynamicArray<int>::Swap' : function does not take 2 arguments.
It's strange for me, because I can call this function with 2 arguments in main function. Does anyone know what is the reason of that?
#include <iostream>
#include <stdexcept>
using std::cout;
using std::cin;
using std::endl;
template <typename T>
class DynamicArray;
template <typename T>
inline void Swap(DynamicArray<T>& lhs, DynamicArray<T>& rhs) {
lhs.Swap(rhs);
}
template <typename T>
class DynamicArray {
public:
DynamicArray(size_t Size = 0, T Content = T())
: m_Size(Size), m_Array(Size ? new T[m_Size] : nullptr) {
for (size_t i = 0; i < m_Size; ++i) {
m_Array[i] = Content;
}
}
DynamicArray(const DynamicArray<T>& rhs)
: m_Size(rhs.m_Size), m_Array(m_Size ? new T[m_Size] : nullptr) {
std::copy(rhs.m_Array, rhs.m_Array + m_Size, m_Array);
}
DynamicArray(DynamicArray<T>&& rhs)
: DynamicArray<T>() {
this->Swap(rhs);
//Swap(*this, rhs); //C2660
}
DynamicArray<T>& operator= (DynamicArray<T> rhs) {
this->Swap(rhs);
//Swap(*this, rhs); //C2660
return *this;
}
~DynamicArray() {
delete [] m_Array;
}
void Swap(DynamicArray<T>& rhs) {
std::swap(m_Size, rhs.m_Size);
std::swap(m_Array, rhs.m_Array);
}
private:
size_t m_Size;
T* m_Array;
};
int main() {
DynamicArray<int> DA1(4, 64);
DynamicArray<int> DA2(2, 33);
DA1 = std::move(DA2); //using move constructor
DynamicArray<int> DA3(8, 4);
DynamicArray<int> DA4(2, 55);
DA3 = DA4; //using assignment operator
Swap(DA1, DA3); //here I can call this function with 2 arguments
cout << endl;
system("pause");
}
To specify that you want to call the global Swap, you should prefix it perhaps with the scope resolution operator ::, like this ::Swap(...).
It's been a long while since I last coded in c++ but I believe the member Swap method takes precedence in the resolution of the Swap symbol, when it's used within a member method.
To explicitly use std::swap function try:
void Swap(DynamicArray<T>& rhs)
{
using std::swap;
std::swap(m_Size, rhs.m_Size);
std::swap(m_Array, rhs.m_Array);
}
DynamicArray(DynamicArray<T>&& rhs)
: DynamicArray<T>()
{
this->Swap(rhs);
}
...
Swap<int>( DA1, DA3 );
but I would remove global inline void Swap(DynamicArray<T> and start using:
DA1.Swap( DA3 );
I am learning C++, and learned that int-types are just premade classes. So I thought maybe i should try to create one.
What I want to do basically is a
normal class of int
int x;
x=7;
cout << x;
// Output is 7 on screen.
so similarly...
abc x;
x=7;
cout << x;
What would I put in
class abc{
\\ HERE!!!!!!
};
so I could do this
class SomeClass {
public:
int x;
SomeClass(int x) {
this->x = x;
}
};
int main(int argc, char *argv[]) {
SomeClass s = 5;
cout << s.x << "\n"; // 5
s = 17;
cout << s.x << "\n"; // 17
return 0;
}
But as you can see I have to use s.x to print the value - I just want to use 's'.
I am doing it as an experiment, I don't want to hear about how this method is good or bad, pointless or revolutionary, or can 't be done. I remember once I did it. But only by copying and pasting code that I didn't fully understand, and have even forgotten about.
and learned that int, types, are just premade classes
This is completely false. Still, you have complete control on how your class will behave in expressions, since you can overload (almost) any operator. What you are missing here is the usual operator<< overload that is invoked when you do:
cout<<s;
You can create it like this:
std::ostream & operator<<(std::ostream & os, const SomeClass & Right)
{
Os<<Right.x;
return Os;
}
For more information, see the FAQ about operator overloading.
the << and >> are basically function names. you need to define them for your class. same with the +, -, * and all the other operators. here is how:
http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html
You need to overload operator<< for your class, like so:
class abc
{
public:
abc(int x) : m_X(x) {}
private:
int m_X;
friend std::ostream& operator<<(std::ostream& stream, const abc& obj);
};
std::ostream& operator<<(std::ostream& os, const abc& obj)
{
return os << obj.m_X;
}
You don't have to friend your operator<< overload unless you want to access protected/private members.
You must define in your class abc cast operator to int and assignment operator from int, like in this template class:
template <class T>
class TypeWrapper {
public:
TypeWrapper(const T& value) : value(value) {}
TypeWrapper() {}
operator T() const { return value; }
TypeWrapper& operator (const T& value) { this->value = value; return *this; }
private:
T value;
};
int main() {
TypeWrapper<int> x;
x = 7;
cout << x << endl;
}
You want to overload the output operator:
std::ostream& operator<< (std::ostream& out, SomeClass const& value) {
// format value appropriately
return out;
}
I have several types that share common behaviour and with same constructors and operators. Some look like this:
class NumberOfFingers
{
public:
void operator=(int t) { this->value = t; }
operator int() const { return this->value; }
private:
int value;
};
NumberOfToes is identical.
Each class has different behaviour, here is an example:
std::ostream& operator<<(std::ostream &s, const NumberOfFingers &fingers)
{
s << fingers << " fingers\n";
}
std::ostream& operator<<(std::ostream &s, const NumberOfFingers &toes)
{
s << toes << " toes\n";
}
How can I minimise the duplication in the class definitions, whilst keeping class types distinct? I don't want to have NumberOfFingers and NumberOfToes derive from a common base class because I lose the constructor and operators. I would guess a good answer would involve templates.
Yes, you are correct in that it would involve templates :)
enum {FINGERS, TOES...};
...
template<unsigned Type> //maybe template<enum Type> but I havent compiled this.
class NumberOfType
{
public:
void operator=(int t) { this->value = t; }
operator int() const { return this->value; }
private:
int value;
};
...
typedef NumberOfType<FINGERS> NumberOfFinger
typedef NumberOfType<TOES> NumberOfToes
... so on and so forth.
Is nesting overloaded operators possible ? I would like to nest << inside a ()
template<class T>
struct UnknownName
{
T g;
T&operator<<(std::ostream&os, const T&v){return os<<v;}
bool operator()(const T&v)
{
if(v==g)
//do the streaming << then return true
else return false;
}
};
Would you please help me out ? I am afraid my example is unreal enough to you, please just ask if you still have any doubts. Sincerely.
I can't really tell what you're asking, but I assume you mean write a class to the ostream& that gets passed to operator<<. First you have to make up a way to convert a T to a string representation. I'll assume the function TToString does that.
template<class T>
struct UnknownName
{
T g;
bool operator()(const T&v)
{
if(v==g) {
cout << v;
return true;
}
return false;
}
friend std::ostream& operator<<(std::ostream& os, const T& v) {
return os << TToString(v);
}
};
Sorry if I misinterpreted your question.
The best I can think of would be to have operator<< return a specific type, and then overload operator() to accept that type:
#include <cstdio>
namespace {
struct Foo {
struct Bar {
int i;
};
Foo& operator()(const Bar& b)
{
std::printf("bar, %d\n", b.i);
return *this;
}
// obviously you don't *have* to overload operator()
// to accept multiple types; I only did so to show that it's possible
Foo& operator()(const Foo& f)
{
std::printf("foo\n");
return *this;
}
};
Foo::Bar operator<<(const Foo& f, const Foo& g)
{
Foo::Bar b = { 5 };
return b;
}
}
int main()
{
Foo f, g, h;
f(g << h);
f(g);
}
This isn't a common idiom, to say the least.