【问题标题】:Trouble combining templates and class function overloading结合模板和类函数重载的麻烦
【发布时间】:2016-11-07 11:54:14
【问题描述】:

下面的代码工作正常,按预期打印出 50。然而,我不明白的是,为什么不能编写相同的程序,只需对这段代码稍作改动。建议的两行代码被标记为错误代码 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 重载成员函数。这应该只返回一个 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;
}

【问题讨论】:

  • 错误代码 1:返回错误类型。错误代码 2:为您想要处理的任何类型实现 ostream

标签: c++ function templates overloading operator-keyword


【解决方案1】:

您必须修改addStuff,使其返回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) {}

编辑: 如果不想改变成员的类型就改变函数的返回类型,可以使用decltype,让代码更通用:

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

【讨论】:

  • 这里不能用auto吗?
  • 也许......到目前为止,我只将auto 返回类型用于更简单的函数,因此存在不确定性。
  • 嗯是的..但是使用 decltype 你可以知道函数将返回什么类型。
  • 好吧,我都试过了:decltype(auto)(或者我发布的更详细的版本)更好,因为如果成员的类型为 int&(例如),那么函数将返回 int,如果你使用“auto”作为返回类型。
【解决方案2】:

问题出在addStuff 函数中,它返回 MyClass 对象,由 int 变量构造。您需要修改此函数以使用“错误代码”

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) {}

【讨论】:

    【解决方案3】:

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

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

    因此,当您将addStuff(x,y) 放入您的cout 语句时,addStuff 的返回类型被推断为 MyClass。这就是使您的编译器产生“MyClass 类型没有运算符

    如果你想让addStuff返回getVar()的结果,你应该声明它返回int,而不是gen

    【讨论】:

      猜你喜欢
      • 2016-10-06
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多