operator() overload and c'tor ambiguity in function objects - c++

assuming we have the next function object:
class foo{
private:
int counter;
public:
foo(int counter): counter(counter){}
foo& operator=(const foo& ){...}
bool operator() (int variable){....}
}
int main(){
foo f(4);
foo x(5);
x = f(4);
return 0;
}
how does the compiler knows how to respond to:
x = f(5)?
I've been searching for a while on the web and in Stack and haven't found exact answer, if its a repost , tell me and i'll delete the question.

It depends on whether the "(5)" is being used to construct an object or called on an already-existing object:
foo f(5); // calls the constructor
f(5); // calls operator()

I added a simple method called eval to explain it:
class foo {
private:
int counter;
public:
foo(int counter): counter(counter) {}
bool operator() (int variable) {
return variable < counter;
}
bool eval(int variable) {
return variable < counter;
}
};
foo is a class not a method.
an instance of foo can be used like a method.
calling foo(5) will create an instance of foo where the counter = 5.
eval is a member function of foo. (for now this will do the same as the () operator)
You can call eval like this:
foo f = foo(5); // create an instance of `foo`
f.eval(3); // returns true -> 3 < 5
f.eval(0); // returns false -> 6 < 5
You can also use the () operator:
foo f = foo(5); // create an instance of `foo`
f(3); // returns true -> 3 < 5
f(0); // returns false -> 6 < 5
NOTE:
You can also write (but don't do it):
foo f = foo(5); // create an instance of `foo`
f.operator()(3); // returns true -> 3 < 5
f.operator()(0); // returns false -> 6 < 5

Related

How doesn't overloading operator() override class constructor

Having the following class with the operator()(string) function and the constructor X(string):
class X
{
public:
string n;
X(string s) : n(s) {}
void operator() (string s)
{
cout << "func";
}
};
Why doesn't X x("a"),y("b"); raise any errors? How does the compiler knows which function to choose?
X x("a"),y("b");
Is equivalent with
X x("a");
X y("b");
So I will focus on
X x("a");
This is a declaration and initialization of the variable x. Only constructors and conversions (*) are considered.
operator() is the function call operator. It is used to call on a object as if it were a function. So it is used on an existing object. E.g.:
X x("asd"); // <-- constructor call
x("yolo"); // <-- operator() call
As a side note I recommend using the brace init syntax {} to initialize objects:
X x{"asd"};
auto x = X{"asd"};
*) As a bonus, here is an example of an user defined conversion operator used:
struct X { };
struct Y
{
operator X() const { return X{}; }
};
auto test()
{
Y y;
X x(y);
// the above line is equivalent with:
X x = static_cast<X>(y.operator X());
}
I used X x(y) to mimic your example, but again, I recommend:
auto test()
{
Y y{};
X x{y};
}
instead

Initialize parameter into constructor, other than the first one

I want to explicitly change the second parameter in a constructor of a struct, in the following scenario. Is it possible, if so, how?
struct foo{
int x;
int y;
foo(int a=4, int b=6){
x=a;
y=b;
}
};
int main(){
foo *f = new foo();
cout<<f->x<<" "<<f->y<<endl;
//4 6
foo *g = new foo(3,4);
cout<<g->x<<" "<<g->y<<endl;
//3 4
foo *h = new foo(3);
cout<<h->x<<" "<<h->y<<endl;
//3 6
//Can something like this be
//done in C++, if I want
//to change the value of the
//second variable only
foo *k = new foo(b = 13);
return 0;
}
Is it possible, if so, how?
It is not possible with constructor. In general, c++ does not support named keyword arguments to functions, and it is not possible to skip arguments even if they have a default, if you want to pass a non-default after it.
It will be possible without constructor using list initialisation syntax since C++20 using designated initialisers, if you use default member initialisers:
struct foo{
int x = 4;
int y = 6;
};
int main(){
foo f {.y = 4};
}
You can achieve something similar with tag dispatching; No need for future standard:
struct foo{
int x = 4;
int y = 6;
enum Xtag { Xinit };
enum Ytag { Yinit };
foo(int a, int b) : x(a), y(b) {}
foo(Xtag, int a) : x(a) {}
foo(Ytag, int b) : y(b) {}
};
int main(){
foo f(foo::Yinit, 4);
}
A solution using lambda that can be used without modifying an existing class. Following works with your definition of foo:
auto make_foo_x4 = [](int b) {
return foo(4, b);
};
foo f = make_foo_y(4);
The downside is that we have to explicitly repeat the default value of x, so this can break assumptions if the default is changed in class definition.

C++ constructor prototype parameter

For example, there is a class foo :
class foo {
public:
foo (int = 10);
.....
}
The prototype of the constructor has "int = 10" inside. So, what does it mean? Int is just an integer type, isn't? So, isn't that illegal to assign a value to it? I was trying to find such an example in Prata's book, and everywhere else, but I didn't find the explanation.
You can omit the name of parameter in function declaration (in definition too), but still you are able to specify default value of that parameter.
Consider:
void f(int x = 10) {
printf("%d\n", x);
}
void g(int = 10);
void g(int x) {
printf("%d\n", x);
}
int main() {
f();
g();
return 0;
}
Result:
10
10
The same situation is in the constructor case.
So, isn't that illegal to assign a value to it?
There is absolutely no assignment involved here. The = character can have quite different meanings in C++:
Assignment: i = 0;
Initialisation: int i = 0;
Making a member function pure virtual: virtual void f() = 0;
Specifiying default arguments: void f(int i = 0);
The latter is what you have encountered. A constructor can have default arguments like any other normal function.

copy on write using a pointer on integer

I try to implement copy on write using a pointer on integer. But I don't understand how to write the code. The idea is very clear in my head: when I use the default constructor, I create a new instance of the object (number of instances=1) and when I use the copy constructor, I increment the number of instances and make a shallow copy of the object.
class Myclass
{
public:
Myclass(const char * foo, int foo2) : foo(foo), foo2(foo2)
{
(*ref)=1;
}
Myclass(const Myclass& rhs) :foo(rhs.foo),foo2(rhs.foo2)
{
(*ref)++;
}
const char * foo;
int foo2;
int *ref;
};
I begin with C++ and the notion of pointer is completely news for me so I tried this.
But I really don't understand why "ref" is still equal to 1 even if I create a copy of the object witht he copy constructor.
Your default constructor needs to create a new reference count:
ref(new int(1))
And your copy constructor needs to make the new object end up with a pointer to the original object's reference count and to increment it (which you already do):
ref(rhs.ref)
I'm having trouble understanding what you want but I'll try...
I create Myclass foo ("foo",10) and then Myclass foo2(foo). I want
all ref to be equal to 2. Here only the ref of foo2 is equal to 2.
The ref of foo is equal to 1. I think I need a pointer, no?
This can be accomplished with a static variable:
class Myclass
{
public:
Myclass(const char * foo, int foo2) : foo(foo), foo2(foo2)
{
ref += 1;
if (1 == ref) {} // First ref, do something?
}
Myclass(const Myclass& rhs) :foo(rhs.foo),foo2(rhs.foo2)
{
ref += 1;
}
~Myclass() // Decrement on delete
{
ref -= 1;
if (0 == ref) {} // Last reference. Do something?
}
const char * foo;
int foo2;
static int ref;
};
int Myclass::ref = 0; // Initialize to 0
Then....
Myclass foo("foo",10); // ref becomes 1
Myclass foo2(foo); // ref becomes 2
Myclass *foo3 = new Myclass(foo); // ref becomes 3
delete foo3; // ref becomes 2

C++ assigning method in constructor using pointers to other methods: what am I doing wrong?

I wrote the following code:
#include <iostream>
using namespace std ;
class C{
public:
C::C(int) ;
int f1(int);
int f2(int);
int (*f)(int);
}
int C::f1(int x){
return -x ;
}
int C::f2(int x){
return x;
}
C::C(int c){
if (c<0){
f = f1 ;
}
else {
f = f2 ;
}
}
This code doesn't work, but the idea is that I want the method f to be assigned either to f1 or to f2 depending on the value passed to the constructor.
How can I achieve this in C++?
If your member functions are non-static, then you have to declare f as a member function pointer:
int (C::*f)(int);
Given the name m of a member function of class C, you get member function pointers to m by writing:
&C::m
In your case:
if (c<0){
f = &C::f1;
}
else {
f = &C::f2;
}
Here is a live example with the full code.
Invoking your member function through the pointer-to-member f will then require the use of operator ->* or .*. For instance:
int main()
{
C c(42);
(c.*(c.f))(1729);
int (C::*fxn)(int) = c.f;
(c.*fxn)(0);
C* p = &c;
(p->*fxn)(123);
}
Or, from inside a given member function fxn of C:
void C::fxn()
{
// ...
(this->*f)(6);
}
On the other hand, if your functions f1() and f() do not need to work on a specific instance of C, you could leave the declaration of f as is as well as the code in C's constructor, but you would have to mark f1() and f2() as static:
class C
{
public:
C(int);
static int f1(int);
// ^^^^^^
static int f2(int);
// ^^^^^^
int (*f)(int);
};
You can normally do this but you need to mark f1 and f2 as static. Otherwise they need a this pointer which normally can't be stored in the function pointer.
class C
{
public:
C(int);
static int f1(int);
static int f2(int);
int (*f) (int);
};
int C::f1(int x)
{
return -x;
}
int C::f2(int x)
{
return x;
}
C::C(int c)
{
if (c < 0) {
f = f1;
} else {
f = f2;
}
}