Type conversion, constness and overloading mixed

Oct 28, 2012 at 2:10pm
Hi geeks!)

Could someone describe what is the general rules for solving the following?

It looks like in first case the type conversion is avoided and const function is called for non-const object, but in second the precedence is for non-const argument with type conversion allowed...

What is the output of the following C++ program?
#include <iostream>

class A
{
public:
A(int i) : m_i(i) { }

public:
int operator()(int i = 0) const { return m_i + i; }

operator int () const { return m_i; }

private:
int m_i;

friend int g(const A&);
};

int f(char c)
{
return c;
}

int g(const A& a)
{
return a.m_i;
}

int main()
{
A f(2), g(3);

std::cout << f(1) << g(f) << std::endl;

return 0;
}
Answer: 35
Oct 28, 2012 at 2:28pm
I believe that the answer is compiler-specific and is undefined by the C++ standard because you're changing the value of f.m_i and using the value in two separate occurances in the same statement.

To describe what is happening, we should first get rid of the stuff that you don't need in the code above.

Delete this: The functions aren't ever called.
1
2
3
4
5
6
7
8
int f(char c)
{
return c;
}
int g(const A& a)
{
return a.m_i;
}


Also delete friend int g(const A&); as it isn't used.

You end up with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

class A
{
public:
  A(int i) : m_i(i) { }
  
public:
  int operator()(int i) const { return m_i + i; }
  operator int ()       const { return m_i; }
  
private:
  int m_i;
};

int main()
{
  A f(2), g(3); // f.m_i = 2, g.m_i = 3
  
  std::cout << f(1) // calls int operator()(int i), f.m_i is now 3
            << g(f) // calls operator int() for f which returns 2, 
                    // then calls int operator()(int i), g.m_i is now 3+2 = 5. 
            << std::endl;
  
  return 0;
}


The operator int() for f returns 2 because the functions in line 21 are excecuted BEFORE the functions in line 20. Which function is excecuted first is not specified in the C++ standard.
Last edited on Oct 28, 2012 at 2:32pm
Oct 28, 2012 at 3:13pm
Ok, let's assume that there is
f(1);
g(f);
so getting rid of calling sequence ambiguity.

What I don't understand is why are you saying "Delete this: The functions aren't ever called", what's the rule to choose the class's methods instead of global functions?

Thank you!
Oct 28, 2012 at 3:21pm
Your code has nothing to do with class methods VS global functions
1) Your class doesn have methods
2) You local variables in main are named exactly the same as global functions
*obviously* the local variable names are going to be used. So f, g are referring to the object of class a in std::cout << f(1) << g(f) << std::endl; and not the functions f, g
Oct 28, 2012 at 3:55pm
To elaborate on codewalker's explanation,

You have int g(const A& a); in the global scope. You also have A g; in the local scope which will support g(f); through a few operator functions defined in the class. When an ambiguity exists, the compiler will generally take the local scope versions and give you a warning when you compile.

At one point I had this problem in some code that I was editing:
1
2
3
4
5
6
7
8
9
10
11
12
int a;
void somefunction()
{
    int a;
    a = 5;
}
int main()
{
    a = 0;
    somefunction();
    cout << a;
}

Since the local definition in somefunction() was defined at the very top of the function which was several hundred lines from where it was set, this was VERY hard to debug and it took a while to figure out why the global a wasn't being set. This is a similar (and simplified) version of what we are explaining to you with the ambiguous function calls.
Last edited on Oct 28, 2012 at 3:55pm
Oct 28, 2012 at 7:58pm
Got it. Thanks!
Oct 28, 2012 at 8:36pm
Stewbond wrote:
because you're changing the value of f.m_i and using the value in two separate occurances in the same statement.
There is no such thing. The methods are const, that means that you can't modify the state of the object.
The behaviour is well defined

Shiva dzhee wrote:
const function is called for non-const object,
That's expected, as you didn't provide an overload for non-const object
Oct 28, 2012 at 9:17pm
closed account (zb0S216C)
ne555 wrote:
"The methods are const, that means that you can't modify the state of the object."

Not if a data member is mutable.

Wazzak
Topic archived. No new replies allowed.