Why can't I use "->" with "this" and "[ ]"? - c++

I'm playing around with composition, and in one of my classes I have a wrapper around the subscript operator "[ ]" (from std::vector). However, the compiler (g++) gets mad when I say this->[i]. I've worked around this issue by using (*this)[i] instead, but I thought these were synonyms. What am I missing? Here is a small sample code that throws the error (I'm purposely avoiding iterators in newmethod just to simply illustrate my problem).
#include <vector>
#include <iostream>
class A {
private:
std::vector<int> rep;
public:
std::size_t size() { return rep.size(); }
int& operator[](std::size_t index) { return rep[index]; }
void newmethod();
A(size_t n, int m) : rep(n,m) {}
};
void A::newmethod() {
for (std::size_t i=0; i < (this->size()); ++i) {
std::cout << (*this)[i] << " ";
}
for (std::size_t i=0; i < (this->size()); ++i) {
std::cout << this->[i]; << " "; //Causes an error!
}
return;
}
int main() {
A(17,3).newmethod();
return 0;
}

You have to call the operator[] member function directly, something like:
this->operator[](i)

a->b is equivalent to (*a).b. What exactly do you expect to happen when you say a->[b] and it translates to (*a).[b]?

That is not correct, if we look at the draft C++ standard we can see that E1->E2 is equivalent to (*(E1)).E2 and not (*E1)E2, this is covered in section 5.2.5 Class member access paragraph 2:
[...]The expression E1->E2 is converted to the equivalent form (*(E1)).E2;[...]
so what follows -> has to be a member of the class(or a base class), so in this case that would be operator[]:
this->operator[](i)

Related

How to solve "invalid operands to binary expression" in C++?

I have a base class and a sub-class that inherits it. I have overridden the operators <, >, <= and >= in the base class, with the purpose of std::sorting a vector with this class. When I std::sort, I do so by calling std::sort(my_vector.begin(), my_vector.end()).
However, I keep getting the error invalid operands to binary expression ('const my_sub_class' and 'const my_sub_class'). I also get like 8 errors and a whole essay of sub-errors for every place I try to implement the sort. For example, I get in instantiation of member function 'std::__1::greater<my_sub_class>::operator()' requested here, if (__comp(*--__last, *__first)), which seems to be the various sub functions.
I hope I've just missed an include, but apart from #include <vector> (d'uh) and #include <algorithm> I can't figure out what else I need. I have tried the overloaded operators separately through if's, and they work. The vector<my_sub_class> works as well. I've also tried various solutions such as overloading the operators in the sub-class, and supplying an explicit sort function (such as greater<my_sub_class>, own functions, reverse sort order via rbegin() and rend()), but nothing seems to work (although some of my solutions give different errors (too varied to include all here).
EDIT:
Here's some code that reproduces the error
Header File:
#ifndef H_DEBUGGING
#define H_DEBUGGING
class my_class {
public:
void set_value(int in_value);
int get_value();
bool operator < (const my_class & in_my_class);
bool operator > (const my_class & in_my_class);
// Some other stuff
protected:
int mValue;
my_class();
// Some other stuff
};
class my_sub_class: public my_class {
public:
my_sub_class();
// Some other stuff
protected:
// Some other stuff
};
void debug_custom_class_vector();
#endif
Class File:
#include <algorithm>
#include <iostream>
#include <vector>
#include "Debugging.hpp"
my_class::my_class() {
}
void my_class::set_value(int in_value) {
mValue = in_value;
}
int my_class::get_value() {
return mValue;
}
bool my_class::operator < (const my_class & in_my_class) {
return mValue < in_my_class.mValue;
}
bool my_class::operator > (const my_class & in_my_class) {
return mValue > in_my_class.mValue;
}
my_sub_class::my_sub_class() {
}
void debug_custom_class_vector() {
my_sub_class sub_a, sub_b, sub_c;
sub_a.set_value(2);
sub_b.set_value(1);
sub_c.set_value(3);
std::vector<my_sub_class> my_custom_vector;
my_custom_vector.push_back(sub_a);
my_custom_vector.push_back(sub_b);
my_custom_vector.push_back(sub_c);
std::cout << "Unsorted: " << std::endl;
for (int i = 0; i < 3; i++) {
std::cout << i << ": " << my_custom_vector[i].get_value() << std::endl;
}
// std::sort(my_custom_vector.begin(), my_custom_vector.end(), std::greater<my_sub_class>());
std::cout << "Sorted: " << std::endl;
for (int i = 0; i < 3; i++) {
std::cout << i << ": " << my_custom_vector[i].get_value() << std::endl;
}
}
// Some other stuff
When I then run from my main, I get:
Unsorted:
0: 2
1: 1
2: 3
Sorted:
0: 2
1: 1
2: 3
and when I uncomment the std::sort line in the class file, I get the error.
What can I do to solve it?
std::sort requires the operators to be const methods. Declaration
virtual bool operator < (classA a);
virtual bool operator < (const classA& a);
virtual bool operator < (classA& a) const;
All three declarations are not suitable for your case, either won't compile or won't work. You need:
virtual bool operator < (const classA& a) const;
Plus, you'll probably need to make copy/move operators virtual...
Also, to begin with, you shouldn't write virtual comparison operator (it cripples performance, possibly 10~100 times for sort). Better use lambda functions for customized sorting. Only in some really weird cases you have to resort to virtual functions. Honestly, I don't know why you need comparison operator to be virtual for sorting... I think you made an error somewhere.
So you'd better check out lambda functions in C++11 and redesign your code.

Use-case and behavior of `this[i]`

I want to know what is the use scope of this[i]. I know this is clearly an useless question but let say it for science. What are the behaviors allow by the standard for indexing this ? I didn't find information about it, cppreference.
Stupid example:
#include <iostream>
class foo {
public:
int value;
void bar(std::size_t size, int a) {
for (std::size_t i = 0; i < size; i++) {
this[i].value = a--;
}
}
};
int main() {
foo foos[42];
(*foos).bar(sizeof foos / sizeof *foos, 42);
for (auto &foo : foos) {
std::cout << foo.value << std::endl;
}
return 0;
}
Is it only allow with array ? Maybe. What about heritage ? I think it's undefined behavior. Do you know some use-case ? It's just some questions about this[i], don't answer to these directly if you don't want to.
this is just a pointer. The ptr[n] syntax is identical to *(ptr + n).
Do you know some use-case ?
No, there's no valid reason to use this[n]. The class itself shouldn't assume that the current instance is part of an array or that there are other instances close by in contiguous memory.
Design the class in such a way that it will work independently of where/how it is instantiated.
Your code can be modernized/improved significantly.
Use std::array instead of C-style arrays.
Don't do manual pointer arithmetic.
Have foo only deal with the current instance.
Do not use endl unless you want to flush the cout buffer. Use \n instead.
class foo {
public:
int value;
void bar(int a) {
this->value -= a;
}
};
int main() {
std::array<foo, 42> foos;
for (auto &foo : foos) {
foo.bar(1);
std::cout << foo.value << '\n';
}
return 0;
}

Access a vector like an array[] inside a function

I want to access the vector in the "manipulatevector" function below the same way as i access an array with vector[i] and not vector->at(i) in the code below. I have tried to pass the vector directly, and not a pointer as can be done with arrays. But this seem to corrupt the program. Any ideas how this can be achieved? Im new to using the std library, as i mostly have experience from C.
#include <vector>
#include <iostream>
#define vectorsize 5
struct st_test {
int ii;
float dd;
};
void manipulatevector(std::vector<struct st_test> *test) {
test->resize(vectorsize);
for(int i=0;i<vectorsize;i++) {
test->at(i).dd = i*0.4f;
test->at(i).ii = i;
}
}
void manipulatearray(struct st_test test[vectorsize]) {
for(int i=0;i<vectorsize;i++) {
test[i].dd = i*0.4f;
test[i].ii = i;
}
}
void main() {
std::vector<struct st_test> test1;
manipulatevector(&test1);
struct st_test test2[vectorsize];
manipulatearray(test2);
std::cout << "Vector" << std::endl;
for(int i=0;i<vectorsize;i++) {
std::cout << test1.at(i).dd << std::endl;
}
std::cout << "Array" << std::endl;
for(int i=0;i<vectorsize;i++) {
std::cout << test2[i].dd << std::endl;
}
}
Have you tried passing the vector as a reference?
void manipulatevector(std::vector<struct st_test> &test) {
test.resize(vectorsize);
for(int i=0;i<vectorsize;i++) {
test[i].dd = i*0.4f;
test[i].ii = i;
}
}
and
std::vector<struct st_test> test1;
manipulatevector(test1);
You can simply use (*test)[i] instead of test->at(i).
This is not actually the same behavior (at vs operator[]), but you are probably already aware of that.
Pass it as a reference instead of a pointer.
void manipulatevector(std::vector<struct st_test> &test) {
You then use . instead of ->, and things like the overloaded [] operator are usable.
Change the signature of void manipulatevector(std::vector<struct st_test> *test) to void manipulatevector(std::vector<struct st_test>& test). Then you can use the operator[] on the vector.
You can pass the vector by reference and use the [] operator:
void manipulatevector(std::vector<struct st_test>& test) {
test.resize(vectorsize);
for(int i=0;i<vectorsize;i++) {
test[i].dd = i*0.4f;
test[i].ii = i;
}
}
When you passed the vector directly, I presume you passed it by value:
void manipulatevector(std::vector<struct st_test> test) {
which meant any changes made inside manipulatevector() would not be seen by the caller. This would mean:
for(int i=0;i<vectorsize;i++) {
std::cout << test1.at(i).dd << std::endl;
}
would throw a std::out_of_range error, from test.at(i), as test1 would not have vectorsize elements, but zero elements. As there is no exception handling in main() this would have caused the program to crash.
There are different options here. You can pass the vector by reference, which is the simplest and cleaner in code:
void function( std::vector<type>& v )
Now, in some shops the style guide requires that if you are going to modify an argument you pass it by pointer as that makes it explicit at the place of call. In that case there are different options to call operator[]:
void function( std::vector<type> *v ){
(*v)[0] = .... // dereference first
v->operator[](0) = .... // explicitly cal the operator
std::vector<type>& vr =*v;
vr[0] = .... // create reference and use that
The first two are equivalent, with the first being arguably easier to read. The second is equivalent to the first one in that it dereferences the pointer and then accesses the operator, but you are explicitly giving a name to the reference, so it can be reused in the function without having to dereference in all uses. While this technically creates an extra variable, the compiler will most probably optimize the reference away.

Why can't a class have same name for a function and a data member?

Why can't a c++ class have same name for a function and a data member?
class demo{
public:
int size();
private:
int size;
};
int main(){
return 0;
}
C:\Users\S>g++ demo.c
demo.c:5:7: error: declaration of 'int demo::size'
demo.c:3:7: error: conflicts with previous declaration 'int demo::size()'
Suppose you want to take the address of the member-function size(), then you would write this:
auto address = &demo::size;
But it could be very well be the address of the member-data size as well. Ambiguous situation. Hence, it is disallowed by the language specification.
That is not to say that it was impossible for the C++ committee to come up with a solution, but I suppose there is no major gain in doing so. Hence, the Standard simply disallowed it, to keep things simple.
Also, the difference between member-data and member-function becomes less distinguishable visually if one declares the member function size() as:
typedef void fun_type();
struct demo
{
fun_type size; //It looks like a member-data, but it's a member-function
};
void demo::size() //define the member function
{
std::cout << "It is crazy!" << std::endl;
}
int main()
{
demo d;
d.size(); //call the function!
}
Output:
It is crazy!
See the online demo : http://ideone.com/ZjwyJ
Now if we can implement member functions as explained above, then it becomes too obvious even to the naked eye that you cannot add another member with same name as:
struct demo
{
fun_type size;
int size; //error - choose a different name for the member!
};
Wait That is not entirely correct, as the story is not finished yet. There is something less obvious I need to add here. You can add more than one member with same name:
typedef void fun_type0();
typedef void fun_type1(int a);
typedef void fun_type2(int a, int b);
struct demo
{
fun_type0 member; //ok
fun_type1 member; //ok
fun_type2 member; //ok
};
This is completely valid code, as each member is a function of different type, so you can define them as:
void demo::member()
{
std::cout << "member()" << std::endl;
}
void demo::member(int a)
{
std::cout << "member(" << a << ")" << std::endl;
}
void demo::member(int a, int b)
{
std::cout << "member(" << a << ", "<< b << ")" << std::endl;
}
Test code:
int main()
{
demo d;
d.member();
d.member(10);
d.member(200,300);
}
Output:
member()
member(10)
member(200, 300)
Online Demo : http://ideone.com/OM97Q
The conclusion...
You can add members with same name, as long as they're function of different types. This is enabled by a feature called member-function-overloading (or simple function-overloading)1.
1. Unfortunately, the language doesn't provide similar feature, say member-data-overloading, for member data, neither do the language provide cross-member-overloading (that allows member-data and member-function to have the same name — the case in the question).
So here a question naturally arises: do they not cause ambiguity problem? Yes, they do. But the point to be noted is that C++ committee came up with a solution to solve this ambiguity-problem, because they saw a huge gain in doing so, (in case of function-overloading).
But the case in the question remains ambiguous, as the committee didn't come up with a solution, as they didn't see any huge advantage in doing so (as noted before). Also, when I said "C++ committee came up with solution", I do NOT mean that the solution has been Standardized, I merely mean that they knew how the compilers can solve it, and how complex the solution would be.
because if you use size in your class somewhere then the compiler does not know what to do. It can be either the int-data-member or it can be the function-pointer. So the compiler is not able to seperate both kind
As an example (Not maybe the best but it might explain it visually):
class Size {
std::size_t size_;
public:
Size(std::size_t s = std::size_t() ) : size_(s){}
std::size_t operator()() const {
return size_;
}
void operator()(std::size_t s) {
size_ = s;
}
};
class Demo {
public:
Size size;
};
int main() {
Demo d;
d.size(10);
std::size_t size = d.size();
return 0;
}
Basically the variable could be callable as well. So there is no way for the compiler to know your intentions.
Of course this is defined by the language that it shall not be possible to have the same name as identifier within the same scope.

Problem with operator overloading

What is the problem with this code ? this code is giving me lots of syntax errors. Also I would like to know why functors are used in C++.
class f
{
public:
int operator(int a) {return a;}
} obj;
int main()
{
cout << obj(0) << endl;
}
You're missing an extra pair of parenthesis when declaring operator(). The name of the function is operator(), and it still needs the list of parameters after it. Thus it should look like:
int operator()(int a) {return a;}
Function objects (a.k.a. functors) like this are typically used where you'd use a pointer to a function. However, they have the advantage that they can use inheritance and they encapsulate state as well. Often, well designed class or function templates will be able to use them almost interchangeably with function pointers. However, a good optimizer can typically produce better code when a template object is used.
For a fairly sophisticated example of how you might use function objects, have a look at expression templates.
Here's a small, somewhat contrived example of how they can use inheritance:
struct unary_int_func {
virtual int operator()(int i) = 0;
};
struct negate : public unary_int_func {
int operator()(int i) {return -i;}
};
struct one_plus : public unary_int_func {
int operator()(int i) {return i+1;}
};
void show_it(unary_int_func &op, int v) {
cout << op(v) << endl;
}
In this case, we create a base class with the operator as a pure virtual function. Then we derive to concrete classes that implement it. Code such as show_it() can then use any instance of a class derived from this base. While we could just have used a pointer to a function that takes an int and returns an int, this is more typesafe. Code that uses the function pointer would accept any such function pointer, whereas this way we can define a whole new hierarchy that maps an int to an int:
struct a_different_base_class {
virtual int operator()(int i) = 0;
};
but instances of this would not be interchangeable with instances of unary_int_func.
As for state, consider a running sum function:
struct running_sum : public unary_int_func {
int total;
running_sum() : total(0) {}
int operator()(int i) {return total += i;}
};
int main()
{
running_sum s;
cout << s(1) << endl;
cout << s(2) << endl;
cout << s(3) << endl;
cout << s(4) << endl;
}
Here, the instance of running_sum keeps track of the total. It will print out 1, 3, 6 and 10. Pointers to functions have no such way of keeping state between distinct invocations. SGI's STL page on function objects has a similar example to my running sum one, but shows how you can easily apply it to a range of elements in a container.
Functors are basically functions with states. Their biggest usage is in STL and Boost libraries. For example std::sort takes a type of functor called Comparator. In this context, perhaps a function object could have been passed instead but functor offers more flexibility by means of the data members you can have and manipulate with subsequent calls to the same functor. Functors are also used to implement C++ callbacks.
As you already have figured out the issue in your operator overloading code, I would rather try to address your doubt regarding functors.
Functor is a short for 'function pointer'.
These are widely used to provide a handle to customize the behavior of an algorithm, for example the sorting algorithms in STL use functor as parameter and the user (programmer) can implement the function to tell the algorithm the result of comparison for 2 elements.
because int operator(int) is effectively equal to int int #something_missing_here#(int)
operator is a reserved keyword and not qualifier as valid function identifier/name when used alone.
I would say it is used to make compiler understand that given expression are function declaration despite the invalid identifiers used (c++ only allow alphabet and underscore as first character in naming)
A functor is an object (instance of class or struct) that typically overloads the operator(). The difference between a functor and a normal function is that because a functor is an object, it can maintain state between calls.
Because a functor is an object, rules of inheritance apply as well and you can use this to your advantage.
A functor is also useful when you use the STL. std::sort, std::for_each, etc allow you to process the contents of an entire container (arrays included). Here's an example from cplusplus.com:
// for_each example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void myfunction (int i) {
cout << " " << i;
}
struct myclass {
void operator() (int i) {cout << " " << i;}
} myobject;
int main () {
vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
cout << "myvector contains:";
for_each (myvector.begin(), myvector.end(), myfunction);
// or:
cout << "\nmyvector contains:";
for_each (myvector.begin(), myvector.end(), myobject);
cout << endl;
return 0;
}
Try this:
class f
{
public:
int operator(int a) {return a;}
};
int main()
{
f obj;
cout<<obj(0)<<endl;
}