【问题标题】:Ambiguous overload for operator>>运算符的模棱两可的重载>>
【发布时间】:2014-02-09 03:13:10
【问题描述】:

我开始学习 C++,但在下面找不到错误的原因。这段代码在《自学 C++》一书中。

main.cpp:13: 错误:'std::cin >> (int)ip' 中'operator>>' 的重载不明确

#include<iostream>

using namespace std;

enum ignition_parts {distributor=1,cap,points,plug,condenser,coil,wires,done};


 main() {

 ignition_parts ip;
 do{
 cout << "\nInsira no item (1-7, 8 para sair):";
 std::cin >> (int)ip;
 switch(ip){

     case distributor: cout<< "Distribuidor";
     break;

     case cap: cout<< "Tampa";
     break;

     case points: cout << "Pontos";
     break;

     case plug:cout << "Vela";
     break;

     case condenser: cout<<"Condensador";
     break;

     case done: break;

     default: cout << "No item ignorado";
     break;

     }

     } while (ip != done);

}

【问题讨论】:

  • 你不应该得到多个匹配项,你应该没有得到匹配项。
  • @chris 有很多匹配项需要 /equally bad/ 隐式转换。欢迎来到 C++ 地狱 :)
  • @sehe,嗯,是的。我的意思是,如果编译器找到同样的 good 匹配项,那么编译器肯定会非常糟糕,从而使调用变得模棱两可。
  • @chris 如果不符合语言规范,那就更难了...
  • @sehe,语言的哪一部分说你可以做到std::cin &gt;&gt; (int)ip;?在某种程度上就像std::cin &gt;&gt; 2;

标签: c++ operator-overloading std cin


【解决方案1】:

所有重载都同样糟糕;)

    std::cin >> (int&)ip;

将是“关闭”,因为您不能分配给右值。

但是,做

    int tmp;
    std::cin >> tmp;
    ip = static_cast<ignition_parts>(tmp);

而不是为了可移植性/定义的行为

这是一个添加了错误处理的版本,并将ip 的输出流提取到它自己的函数中:See it Live on Coliru

#include<iostream>

enum ignition_parts {distributor=1,cap,points,plug,condenser,coil,wires,done};

std::ostream& operator<<(std::ostream& os, ignition_parts ip)
{
    switch(ip) {
            case distributor: return os << "Distribuidor";
            case cap:         return os << "Tampa";
            case points:      return os << "Pontos";
            case plug:        return os << "Vela";
            case condenser:   return os << "Condensador";
            default:          return os << "No item ignorado";
    }
    // unreachable
}

int main() {
    ignition_parts ip;
    do {
        std::cout << "\nInsira no item (1-7, 8 para sair): ";

        int tmp;
        if(std::cin >> tmp) 
        {
            ip = static_cast<ignition_parts>(tmp);

            if (ip == done) {
                break;
            }

            std::cout << ip;
        } else {
            if(std::cin.eof()) {
                break;
            }
            std::cout << "Whoops: invalid input\n";
            std::cin.clear();
            std::cin.ignore(1024, '\n');
        }

    } while(std::cin && ip != done);

}

【讨论】:

    【解决方案2】:

    建议:使用数组进行标识符到字符串的转换。

    std::ostream& operator<<(std::ostream& os, ignition_parts ip)
    {
        static const char * names[] =
        {
           "Nothing",
           "Distribuidor", "Tampa", "Pontos", "Vela", "Condensador"
        }
        // Test ip for validity first.
        os << names[ip];
    }
    

    上面是不安全的,因为如果enum 顺序改变,上表中的映射会产生不正确的结果。此外,如果 enum 已扩展而数组未扩展,则可能会出现运行时缓冲区溢出错误(讨厌)。

    更安全的方法是在表中包含标识符:

    struct Entry
    {
        ignition_parts part_id;
        const char *   name;
    };
    const Entry  name_table[] =
    {
      {distributor, "Distribuidor"},
      {cap,         "Tampa"},
      {points,      "Pontos"},
      {plug,        "Vela"},
      {condenser,   "Condensador"},
    };
    const unsigned number_of_entries =
        sizeof(name_table) / sizeof(name_table[0]);
    

    您在每个条目中搜索匹配的 ID,然后返回表条目的 name 字段。

    此方法的一个好处是您可以在不更改代码的情况下添加条目,并且顺序不相关(条目的顺序无关紧要)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-18
      • 2010-12-10
      • 1970-01-01
      • 2014-09-26
      • 1970-01-01
      • 1970-01-01
      • 2019-09-12
      相关资源
      最近更新 更多