Odd Conditional Operator Bug

Oct 31, 2012 at 10:25pm
This is my first post so bear with me.

What I'm trying to figure out is why "cout << (result.IntCheck() ? result.Float() : result ) << endl;" calls a constructor for a new Fraction object after result.IntCheck() returns true and result.Float() returns a double value.

The reason I know that a constructor is called after result.Float() returns is because I used gnu debugger.

Driver:
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 <cstdlib>
#include <iostream>
#include <fstream>
#include "Fraction.h"
using std::cout;
using std::endl;

#define DATA "fraction270.txt"

int main()
{
    Fraction first, second, result;
    char op;
    std::ifstream dataFile( DATA, std::ios::in );
    if ( !dataFile )
    {
       std::cerr << DATA << "could not be opened." << endl;
       exit( 1 );
    }

    dataFile >> first >> op >> second;
    result = first * second;
    cout << (result.IntCheck() ? result.Float() : result ) << endl;
    system("PAUSE");
    return 0;
}


Class Definition:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "Fraction.h"
#include <iostream>
#include <string>
#include <cstdlib>
#include <cmath>
using std::ostream;
using std::istream;

void Fraction::Assign(int n, int d)
{
    num = n;
    if (d != 0) 
            den = d;
    else den = 1;
} 

Fraction::Fraction(int n, int d)
{
    Assign(n, d);
}

ostream& operator<<( ostream& output, const Fraction& fraction )
{
    output << fraction.num << "/" << fraction.den;
    return output;
}

istream& operator>>( istream& input, Fraction& fraction )
{
    std::string buffer;
    input >> buffer;
    fraction.Assign( std::atoi(buffer.substr(0, buffer.find("/")).c_str()), 
                     std::atoi(buffer.substr(buffer.find("/") + 1).c_str()));
    return input;
}

const Fraction Fraction::operator*(Fraction right)
{
    Fraction product((num *  right.num), (den * right.den));
    product.Simplify();
    return product;
}

double Fraction::Float()
{
    return (double)num/den;
}

void Fraction::Simplify()
{
    if(num != 0)
    {
        if(den % num == 0)
        {
            den /= num;
            num = 1;
        }
        else
        {
            int factor;
            if(num < den)
                factor = std::sqrt(num);
            if(den < num)
                factor = std::sqrt(den);
            while(factor > 1)
            {
                if((den % factor == 0)&&(num % factor == 0))
                {
                   num /= factor;
                   den /= factor;
                }
                else
                    --factor;
            }
        }
    }
}

bool Fraction::IntCheck()
{
    if(num % den == 0)
            return true;
    else
        return false;
}


Class Header:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iosfwd>

class Fraction
{
    friend std::ostream& operator<<( std::ostream& output, const Fraction& fraction );
    friend std::istream& operator>>( std::istream& input, Fraction& fraction );
public:
    Fraction(int n = 0, int d = 1);
    void Assign(int n, int d);
    const Fraction operator*(Fraction right);
    double Float();
    void Simplify();
    bool IntCheck();
private:
    int num;
    int den;
};


Expected Output:
6


Actual Output:
6/1
Oct 31, 2012 at 10:46pm
The conditional operator

result.IntCheck() ? result.Float() : result

shall return the common type for operands result.Float() and result.

Expression result.Float() has type double while expression result has type Fraction. An object of type Fraction can not be converted to type double because your class has no such conversion function. However an object of type double can be converted to an object of type Fraction because the class contains constructor that takes one argument

Fraction(int n = 0, int d = 1);

So the common type for the expression will be Fraction. The compiler creates a temporary object of type Fraction using the following call

Fraction( result.Float() );
Nov 1, 2012 at 12:23am
Thanks. Neither my professor nor my textbook mention a common return type. Nor wikipedia... Nor http://www.cplusplus.com/doc/tutorial/operators/ ...

I consider this an oversight.
Nov 1, 2012 at 11:54am
If you can translate from Russian to English for example by means of google translate then you can read my topic about a bug in std::common_type in MS VC++ 2010. I think it would be useful.

http://cpp.forum24.ru/?1-3-0-00000051-000-0-0-1343642437
Nov 1, 2012 at 2:37pm
cppreference has an explanation of the conditional operator's return type:

http://en.cppreference.com/w/cpp/language/operator_other#Conditional_operator
Topic archived. No new replies allowed.