C++ operator overloading [], where is the data parameter to assign? - c++

I want to add a overload the operator [] in my class. Operator overloading is not something I've had to do before.
I want to write an implementation to do the following:
myclass a;
a["test"] = 123;
int test = a["test"];
So far in my class the prototype looks like this:
string operator[](const char* cpszLabel);
The implementation isn't complete and looks like this:
string myclass::operator[](const char* cpszLabel) {
string strContent;
if ( cpszLabel != nullptr ) {
}
return strContent;
}
What I'm not sure about is how to reference the data that is being assigned or does this require overloading the '=' too?
I've added an overload for the '=' operator, but this doesn't get called:
Prototype:
string operator=(int intData);
Implementation:
string myclass::operator=(int intData) {
char szString[24];
sprintf(szString, "\"%d\"", intData);
return string(szString);
}

In a["test"] = 123;, the "receiver" of the assignment is the object that's returned from the lookup, which is a string.
You can't overload string's assignment operator.
But, as is well known, every problem can be solved by introducing a level of indirection.
You can store a type of your own instead of std::string, and let that handle the conversion.
A very small example as illustration:
struct Data
{
template<typename T>
Data& operator=(const T& rhs)
{
std::ostringstream os;
os << rhs;
value = os.str();
return *this;
}
operator const char*() const { return value.c_str(); }
std::string value;
};
struct Container
{
Data& operator[] (const std::string& s) { return table[s]; }
std::map<std::string, Data> table;
};
int main()
{
Container cont;
cont["foo"] = "bar";
cont["baz"] = 123;
cont["goo"] = 5.5;
for (auto v: cont.table)
{
std::cout << v.first << " --> " << v.second << '\n';
}
}
Output:
baz --> 123
foo --> bar
goo --> 5.5

You need to arrange things so operator[](const char* cpszLabel) returns a reference to something in your class.
int& operator[](const char* cpszLabel);
is probably a better prototype.
You can then modify that "something" in your class via that reference. To be honest though what you want can be achieved with
typedef std::map<std::string, int> myclass;
and most folk don't bother with the typedef, especially now that we have auto. If you want to use a std::map as a member variable in the class (in order to reduce functionality &c.), then the following is a starting point:
class myclass
{
std::map<std::string, int> m_data;
public:
int& operator[](const char* cpszLabel)
{
return m_data[cpszLabel];
}
};

Related

Does C++ have an equivilent to Python's __setitem__

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.
There's an interesting discussion about what's possible (and what's not) in C++ with subscript operators in this article.
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.

Want to assing std::string but compiler thinks is bool [duplicate]

This question already has an answer here:
String literal matches bool overload instead of std::string
3 answers
Boolean and String Overloads of the Assignment Operator (C++)
2 answers
I pretend to write a class which can act as a variant type.
Everything is working fine, but when I try to assing a string, the method that gets called is the one with bool as a parameter:
class value_t {
public:
value_t operator=(const int& integer) {
std::cout<<"integer"<<std::endl;
return *this;
};
value_t operator=(const std::string& str) {
std::cout<<"string"<<std::endl;
return *this;
};
value_t operator=(const bool& boolean) {
std::cout<<"boolean"<<std::endl;
return *this;
};
};
value_t val;
val = "Hola mundo";
And the output is:
boolean
Why is not the string assign operator method get called?
Thank you
A string literal like "Hola mundo" is a const char [], which decays to const char *.
The language standard defines an implicit conversion from any pointer to a bool.
The compiler chooses your bool operator as a better choice because calling your std::string operator would require the compiler to construct a temporary std::string object, while calling the bool operator does not.
To do what you want, add another operator for const char * so the compiler doesn't have to convert at all (it can optionally call the std::string operator if desired):
value_t operator=(const char* str) {
std::cout << "char*" << std::endl;
return *this;
};
value_t operator=(const char* str) {
return operator=(std::string(str));
};
Otherwise, you have to pass in a std::string explicitly:
val = std::string("Hola mundo");
On a side note, your operators should be returning a value_t& reference instead.

Operator Overloading C++: write-only version

I am overloading operators for a data structure, so I have the standard function declarations:
T & operator[](int i); //used for regular objects
const T & operator[](int i) const; // used for const objects
So what I want to do is to have a two versions of operator[] for regular objects: one that does something different when the operator[] is used to write rather than read.
I have been reading that this is possible, but I have not yet seen any code.
I have seen many times this question asked, and I have seen the answer " 'operator[] const' version is used for reading" --> but this is not true; it is used only with const instantiations of the class.
Can anyone offer guidance on detecting the write event to trigger different behavior?
Is perhaps the trick in the copy constructor?
As several have mentioned in the comments, you need to return a proxy, AKA smart reference, which is wrapper to the actual type T that you want, and has a link to the original object on which [] operator was called.
When the proxy is on the left side of an =, compiler will invoke its assignment operator to type T.
When the proxy is on the right side of an = , compiler will invoke its cast operator to type T.
Here is a String example, I think as described in Scott Meyer's Effective C++
The first line of main should print "Writing to the String"
The second line will print "Reading from the String"
struct String
{
char text[10];
struct CharReference; // forward declare char proxy class
CharReference String::operator[] ( int index );
void print() { printf("%s",text ); }
};
struct String::CharReference
{ CharReference( String * s, int i ) ;
operator char ();
const char & String::CharReference::operator = ( const char & rhs ) ;
int index;
String *theString;
};
const char & String::CharReference::operator = ( const char & rhs )
{
printf("Writing to the string\n");
theString->text[index] = rhs;
return rhs;
}
String::CharReference::operator char()
{
printf("Reading from the string\n");
return theString->text[index];
}
String::CharReference::CharReference( String * s, int i ):theString(s), index(i) {}
String::CharReference String::operator[] ( int index )
{
return CharReference( this, index);
}
int _tmain(int argc, _TCHAR* argv[])
{
String s;
s[0] = 'A';
char c = s[0];
return 0;
}
The class holding the objects cannot get the information whether your access to the returned object is read or write access.
Only the object itself has some notion of "in which context am I used" via the member function qualifiers.
Ref-qualifiers
const/volatile qualifiers
You can use this in a proxy class.
#include <vector>
#include <type_traits>
#include <iostream>
template <class T, class U = T, bool Constant = std::is_const<T>::value>
class myproxy
{
protected:
U& m_val;
myproxy& operator=(myproxy const&) = delete;
public:
myproxy(U & value) : m_val(value) { }
operator T & ()
{
std::cout << "Reading." << std::endl;
return m_val;
}
};
template <class T>
struct myproxy < T, T, false > : public myproxy<T const, T>
{
typedef myproxy<T const, T> base_t;
public:
myproxy(T & value) : base_t(value) { }
myproxy& operator= (T const &rhs)
{
std::cout << "Writing." << std::endl;
this->m_val = rhs;
return *this;
}
};
template<class T>
struct mycontainer
{
std::vector<T> my_v;
myproxy<T> operator[] (typename std::vector<T>::size_type const i)
{
return myproxy<T>(my_v[i]);
}
myproxy<T const> operator[] (typename std::vector<T>::size_type const i) const
{
return myproxy<T const>(my_v[i]);
}
};
int main()
{
mycontainer<double> test;
mycontainer<double> const & test2(test);
test.my_v.push_back(1.0);
test.my_v.push_back(2.0);
// possible, handled by "operator=" of proxy
test[0] = 2.0;
// possible, handled by "operator T const& ()" of proxy
double x = test2[0];
// Possible, handled by "operator=" of proxy
test[0] = test2[1];
}
Prints
Writing
Reading
Reading
Writing

Overload operator[] for Char assignment - C++

I am fairly new to C++, although I do have some experience programming. I have built a Text class that uses a dynamic char* as it's main member. The class definition is below.
#include <iostream>
#include <cstring>
using namespace std;
class Text
{
public:
Text();
Text(const char*); // Type cast char* to Text obj
Text(const Text&); // Copy constructor
~Text();
// Overloaded operators
Text& operator=(const Text&);
Text operator+(const Text&) const; // Concat
bool operator==(const Text&) const;
char operator[](const size_t&) const; // Retrieve char at
friend ostream& operator<<(ostream&, const Text&);
void get_input(istream&); // User input
private:
int length;
char* str;
};
The issue I am having is I don't know how to use operator[] to assign a char value at the given index that's passed in. The current overloaded operator operator[] is being used to return the char at the index supplied. Anyone have experience with this?
I would like to be able to do something similar to:
int main()
{
Text example = "Batman";
example[2] = 'd';
cout << example << endl;
return 0;
}
Any help and/or advice is appreciated!
Solution provided - Thanks a bunch for all the replies
char& operator[](size_t&); works
You need to provide a reference to the character.
#include <iostream>
struct Foo {
char m_array[64];
char& operator[](size_t index) { return m_array[index]; }
char operator[](size_t index) const { return m_array[index]; }
};
int main() {
Foo foo;
foo[0] = 'H';
foo[1] = 'i';
foo[2] = 0;
std::cout << foo[0] << ", " << foo.m_array << '\n';
return 0;
}
http://ideone.com/srBurV
Note that size_t is unsigned, because negative indexes are never good.
This article is the definitive guide to operator overloading in C++ (which, to be honest, is mainly boilerplate code for syntactic sugar). It explains everything that is possible:
Operator overloading
Here's the portion that is of interest to you:
class X {
value_type& operator[](index_type idx);
const value_type& operator[](index_type idx) const;
// ...
};
And yes, this is possible, for the many of the STL containers (the vector for example), allow for array subscript notation to access data.
So you can do something along the lines of this:
char & operator[]( size_t i )
{
return *(str + i);
}
You should overload operator[] as non const method and return a reference from it
char& operator[](const int&);

Access class member “directly” like std::string

I would like the following code to be equivalent:
f = "abc";
h.data = f;
EDIT: I'd also like the ability to do the following:
f += "def"; // f.data == "abcdef";
std::string s = f; // s = "abcdef";
std::cout << f << std::endl;
std::cin >> f;
std::vector<std::string> v (f);
v.push_back(h);
// This would be overkill.
printf("%s", (f + std::string("...\n")).c_str());
Would I need to "inherit" std::string or something? (I'm new to this stuff, so could you show me how?)
Here's my class:
class Foo
{
public:
std::string data;
} f, h;
EDIT: I'd also like the ability to do the following: [...]
[ This would have been better served as a new question but I don't think you could have foreseen that. ]
No, you don't need to inherit from std::string. One possible way to do what you want is to add a conversion operator. (I won't address how to implement operator+=, it can be looked up elsewhere.)
class foo {
std::string data;
public:
foo&
operator=(std::string); // See Kerrek's answer for implementation
operator std::string const&() const
{ return data; }
};
This will do what you want. But I strongly advise you not to use that. Surprising implicit conversions are frowned upon; I recommend reading Herb Sutter to learn why.
Alternatively you can make the conversion operator explicit (as in, declaring it explicit operator std::string const&() const;) to suppress implicit conversions. But that's quite less convenient and readable than adding a member function with an appropriate name:
class foo {
// as before
operator std::string const&() const
{ return as_string(); }
std::string const&
as_string() const
{ return data; }
};
foo f;
// Contrast the uses:
// std::string s0 = f; Not ok; would be an implicit conversion
std::string s0(f); // Ok; explicit conversion
std::string s1 = f.as_string(); // Ok; std::string s1(f.as_string()) works too
std::vector<std::string> v;
// v.push_back(f); Not ok; would use an implicit conversion
v.push_back(static_cast<std::string const&>(f)); // Ok; inconvenient
v.push_back(f.as_string()); // Ok; convenient
Whatever you choose, I still recommend implementing appropriate operators for working with streams:
std::ostream&
operator<<(std::ostream& os, foo const& f)
{
return os << f.as_string();
}
std::istream&
operator>>(std::istream& is, foo& f)
{
std::string extracted;
if(is >> extracted) {
f = std::move(extracted);
}
return is;
}
Add an assignment operator:
class Foo
{
public:
std::string data;
Foo & operator=(const std::string & s) { data = s; return *this; }
};
Depending on what you want to return you could also define it like this:
std::string & operator=(const std::string & s) { data = s; return data; }
Or even, in C++0x:
std::string & operator=(std::string s) { data = std::move(s); return data; }
The former lets you write: Foo x, y; y = x = "hello";. The latter lets you write: std::string a, b; Foo x; a = x = b;. Take your pick.
If I understand correctly, you want to be able to do:
Foo f;
f = "abc";
In which case, you will need to overload operator=. Something along the lines of:
class Foo
{
public:
void operator= (const std::string &str) { data = str; }
std::string data;
};
Overload the = operator.
You can overload the operator.
But I do subscribe to ESA rules about programming. Anything above the simple stuff (eg. I/O, strings, numbers, booleans) get the objects to have member functions. Makes the code more readable and maintainable.
See http://www.esa.int/TEC/Software_engineering_and_standardisation/TECRFBUXBQE_2.html

Resources