Неоднозначная перегрузка для оператора››

Я начинаю изучать C++ и не могу найти причину ошибки ниже. Этот код есть в книге "Teach Yourself C++".

main.cpp:13: ошибка: неоднозначная перегрузка для «operator>>» в «std::cin >> (int)ip»

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

}

person Frederico Americano    schedule 08.02.2014    source источник
comment
Вы не должны получать несколько совпадений, вы не должны получать совпадений.   -  person chris    schedule 08.02.2014
comment
@chris получает много совпадений, требующих / одинаково плохих / неявных преобразований. Добро пожаловать в ад С++ :)   -  person sehe    schedule 08.02.2014
comment
@sehe, Ну да. Я хотел сказать, что компилятор должен быть очень плохим, если он находит одинаково хорошие совпадения, чтобы вызов был неоднозначным.   -  person chris    schedule 08.02.2014
comment
@chris Было бы намного сложнее, если бы это не соответствовало языковым спецификациям ...   -  person sehe    schedule 08.02.2014
comment
@sehe, какая часть языка говорит, что ты можешь сделать std::cin >> (int)ip;? Это как std::cin >> 2; в каком-то смысле.   -  person chris    schedule 08.02.2014
comment
@chris помни - operator>> это просто функция! Вы можете прекрасно определить void operator>>(std::istream const&, int) {}... coliru.stacked-crooked.com/a/fa91c4349036af74   -  person sehe    schedule 08.02.2014
comment
@sehe, хорошо, я понимаю, к чему ты клонишь, хотя <iostream> ничего подобного не определяет, а std::cin не может неявно преобразовать в любой подходящий арифметический тип для битового сдвига.   -  person chris    schedule 08.02.2014
comment
Спасибо !! Просто ошибка первокурсника.   -  person Frederico Americano    schedule 08.02.2014


Ответы (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]);

Вы ищете в каждой записи соответствующий идентификатор, а затем возвращаете поле name записи таблицы.

Хорошим преимуществом этого метода является то, что вы можете добавлять записи без изменения кода и порядок не зависит (порядок записей не имеет значения).

person Thomas Matthews    schedule 08.02.2014

Все перегрузки одинаково плохи ;)

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

Было бы «близко», так как вы не можете присвоить rvalue.

Тем не менее, сделайте

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

вместо переносимости/определенного поведения

Вот версия с добавленной обработкой ошибок и извлечением потока вывода ip в собственную функцию: см. Прямой эфир на Колиру

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

}
person sehe    schedule 08.02.2014