XenoZergNid
XenoZergNid

Reputation: 56

overloading << operator with template to change output

I've got a class called number and I'm needing help with operator overloading.

template<class T>
class Number{
public:
    Number(T _numerator,T _denominator){
        numerator = _numerator;
        denominator = _denominator;
    }
    ~Number(){
        ;
    }
    T GetData(){
        return numerator/denominator;
    }
    friend std::ostream &operator<<(std::ostream &out, Number c)     //output
    {
        out << c.numerator/c.denominator;
        return out;
    }
    void SetData(T _numerator,T _denominator){
        numerator = _numerator;
        denominator = _denominator;
    }

private:
    T numerator;
    T denominator;
};

that's what I have that works but I would like another operator overloaded like:

template<class X>
friend std::ostream &operator<<(std::ostream &out, Number c)     //output
{
    out << (X)c.numerator/(X)c.denominator;
    return out;
}

that way I can call cout like this(I know I could just change Number's template to a double but that's not what I want):

Number<int> t(10,23);
std::cout << t<double> << "\n";

however that doesn't compile. so is there anyway to use templates like that? or an alternate solution other than just creating a normal function?

Upvotes: 2

Views: 144

Answers (2)

WhozCraig
WhozCraig

Reputation: 66194

You can get close to what you're looking for any number of ways. The exact syntax you want is impossible unfortunately , as the type you desire must be pinned through something (be it a function, a constructed object, whatever).

Vinzenz has shown you how to you can pin it through a member function. This is how you can pin it through an alternate constructor.

#include <iostream>

template<class T>
class Number
{
    // allow friending alternate types
    template<typename> friend class Number;

    friend std::ostream &operator<<(std::ostream &out, Number c)     //output
    {
        out << c.GetData();
        return out;
    }

public:
    Number(T _numerator = 0, T _denominator = 1)
        : numerator(_numerator)
        , denominator(_denominator)
    {
    }

    // constructor for alt-type conversion
    template<typename X>
    Number(const Number<X>& obj)
        : numerator(static_cast<T>(obj.numerator))
        , denominator(static_cast<T>(obj.denominator))
    {
    }

    // getter should be const
    T GetData() const
    {
        return numerator/denominator;
    }

    void SetData(T _numerator,T _denominator)
    {
        numerator = _numerator;
        denominator = _denominator;
    }

private:
    T numerator;
    T denominator;
};

int main()
{
    Number<int> num(10,5);      // regular construction
    Number<float> flt = num;    // alternate type construction

    // operator tests
    std::cout << num << '\n';
    std::cout << flt << '\n';
    std::cout << Number<double>(num) << std::endl; // temp construction

    return EXIT_SUCCESS;
}

Output

2
2
2

Best of luck.

Upvotes: 1

Vinzenz
Vinzenz

Reputation: 2819

I think you're thinking too complicated about it and the way you want to use it, won't work.

When you need it to be Double, make it double, so therefore I added here the new member as()

template<class T>
class Number{
public:
    Number(T _numerator,T _denominator){
        numerator = _numerator;
        denominator = _denominator;
    }
    ~Number(){
        ;
    }
    T GetData(){
        return numerator/denominator;
    }
    friend std::ostream &operator<<(std::ostream &out, Number c)     //output
    {
        out << c.numerator/c.denominator;
        return out;
    }
    void SetData(T _numerator,T _denominator){
        numerator = _numerator;
        denominator = _denominator;
    }

    template<typename U>
    Number<U> as(){
        return Number<U>(U(numerator), U(denominator));
    }

private:
    T numerator;
    T denominator;
};


Number<int> t(10,23);
std::cout << t.as<double>() << "\n";

Upvotes: 1

Related Questions