无法组合模板和 class 函数重载

Trouble combining templates and class function overloading

下面的代码工作正常,按预期打印出 50。然而,我不明白的是,为什么不能通过对这段代码稍作改动来编写同一个程序。建议的两行代码被标记为 Bad code 1 和 2。当将它们替换为它们左侧的当前工作代码时(即在 addStuffmain 中),我收到以下错误:

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

我期望它工作的方式是:当 addStuff(x,y)main() 的(坏的)cout 行被调用时,它首先计算 x+y,其行为由 operator+ MyClass 重载成员函数定义。这应该只是 return 一个 MyClass 对象,然后调用 getVar 就没有问题了。

我在这里错过了什么?

#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;
}

您必须修改 addStuff,使其 return 成为 int,而不是模板参数 gen(即 MyClass):

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

如果你不把gen改成int,那么这个函数就可以正常工作,因为构造函数MyClass(int a)会被显式调用,然后结果会是一个对象输入 MyClass.

显然编译器会说你不能'cout'一个MyClass.

类型的对象

所以我建议你用explicit标记构造函数: 另外你的代码没有编译因为没有默认构造函数,所以添加一个,或者简单地用默认值标记参数:

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

编辑: 如果你不想在改变成员的类型时改变函数的return类型,你可以使用decltype,使代码更通用:

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

问题出在 addStuff 函数中,它 returns MyClass 对象,由 int 变量构造。您需要修改此函数以使用 "bad code"

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

或者为MyClass写一个ostream操作符。为此,您需要修改 getVar 方法,包括友元声明并实现它

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;
}

这样你就不需要修改addStuff函数了。

旁注,你的代码没有为我编译,因为 MyClass 中没有默认构造函数,必须像这样修改构造函数

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

您对第 1 行中应该发生的事情的解释 return (x+y).getVar(); 是正确的。重载的 operator+ 将在参数 x 和 y 上被调用,而 getVar() 将在 operator+ 的结果上被调用。当 x 和 y 是 MyClass 类型时,operator+ 调用 returns 一个 MyClass 类型的对象,因此对 getVar() 的调用有效。

但是,getVar() return 是一个整数。您的函数 addStuff 被指定为 return gen,这是与参数 x 和 y 匹配的相同模板参数。这意味着当 x 和 y 是 MyClass 时,addStuff 函数必须 return MyClass.

因此,当您将 addStuff(x,y) 放入 cout 语句中时,addStuff 的 return 类型被推断为 MyClass。这就是使您的编译器产生 "there is no operator<< for type MyClass."

错误的原因

如果你想addStuff到returngetVar()的结果,你应该将它声明为returnint,而不是gen .