user3317405
user3317405

Reputation: 47

Trouble combining templates and class function overloading

The code below works fine, printing out 50 as expected. What I am not understanding, however, is why the same program can't be written with a couple slight alterations to this code. The two lines of proposed code are marked Bad code 1 and 2. When these are substituted for the current working code to the left of them (i.e. in addStuff and main), I get the following error:

error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream}' and 'MyClass')|

The way I expected it to work was: when addStuff(x,y) gets called in the (bad) cout line of main(), it first evaluates x+y, the behavior of which is defined by the operator+ MyClass overloaded member function. This should just return a MyClass object, which then has no trouble calling getVar.

What am I missing here?

#include <iostream>
using namespace std;

class MyClass
{
public:
    MyClass(){}
    MyClass(int a) : priV(a){}
    MyClass operator+(MyClass otherMC)
    {
        MyClass newMC;
        newMC.priV = this->priV + otherMC.priV;
        return newMC;
    }
    int getVar(){return priV;}
    void setVar(int v){priV=v;}
private:
    int priV;
};

template <class gen>
gen addStuff(gen x, gen y)
{
    return x+y;          //Bad code 1: return (x+y).getVar();
}

int main()
{
    MyClass x(20), y(30);
    cout << addStuff(x,y).getVar() << endl;    //Bad code 2: cout << addStuff(x,y) << endl;
}

Upvotes: 1

Views: 71

Answers (3)

Mattia F.
Mattia F.

Reputation: 1740

You have to modify addStuff so that it returns an int, not the template parameter gen (which will be MyClass):

template <class gen>
int addStuff (gen x, gen y)
{
    return (x + y).getVar ();
}

If you don't change gen into int, then the function will work fine because the constructor MyClass(int a) will be called explicitly and then the result will be an object of type MyClass.

And obviously the compiler will say that you cannot 'cout' an object of type MyClass.

So i suggest you to mark the constructor with explicit: Also your code didn't compile because there is no default constructor, so add one, or simply mark the parameter with a default value:

explicit MyClass (int a = 0) : priV (a) {}

EDIT: If you don't want to change the return type of the function if you change the type of the member, you can use decltype, to make the code more generic:

template <class gen>
decltype (auto) addStuff (gen x, gen y)   //Or decltype (declval<gen> ().getVar ())
{
    return (x + y).getVar ();
}

Upvotes: 1

buld0zzr
buld0zzr

Reputation: 962

Problem is in addStuff function, it returns MyClass object, constructed from int variable. You need to modify this function to work with "bad code"

template <class gen>
int addStuff(gen x, gen y)
{
    return (x+y).getVar();
}

Or write an ostream operator for MyClass. For this you need to modify getVar method, include a friend declaration and implement it

int getVar() const { return priV; }
friend std::ostream& operator<< (std::ostream &out, const MyClass& m);
std::ostream& operator<< (std::ostream& out, const MyClass& m) {
    out << m.getVar();
    return out;
}

This way you don't need to modify addStuff function.

Side note, your code didn't compile for me because there was no default constructor in MyClass, had to modify constructor like this

MyClass(int a = 0) : priV(a) {}

Upvotes: 1

Edward
Edward

Reputation: 6290

Your interpretation of what should happen in line 1, return (x+y).getVar(); is correct. The overloaded operator+ will get called on the arguments x and y, and getVar() will be called on the result of operator+. When x and y are of type MyClass, the operator+ call returns an object of type MyClass, so the call to getVar() works.

However, getVar() returns an int. Your function addStuff is specified to return gen, which is the same template parameter that matches the arguments x and y. This means that when x and y are MyClass, the addStuff function must return MyClass.

Thus, when you put addStuff(x,y) in your cout statement, the return type of addStuff is inferred to be MyClass. This is what makes your compiler produce the error that "there is no operator<< for type MyClass."

If you want addStuff to return the result of getVar(), you should declare it to return int, not gen.

Upvotes: 2

Related Questions