Ошибка C++ c2664 не может преобразовать аргумент 1 из std::string в _Elem *

Я застрял на этом домашнем задании всю неделю. Как только я получаю программу, наконец, запущенную, я понимаю, что, используя только cin >> breed, если в моем вводе есть пробел, это разрушает код (поскольку моя программа требует сбора 3 отдельных переменных, сначала int, затем string и, наконец, bool ). Поскольку это вторая переменная, она портит мой код, используя фразы с белым символом. Когда я пытаюсь изменить его на cin.get или cin.getline, я получаю следующее сообщение об ошибке:

ошибка c2664 "невозможно преобразовать аргумент 1 из std::string в _Elem *"

Ниже приведен рассматриваемый код (средняя строка дает ошибку). Любая помощь будет принята с благодарностью!

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int birthyear;  
    string breed;    
    bool vaccines;  

    cout << "Please enter value for dog's birth year: ";
    cin >> birthyear;
    cout << "What is the breed of the dog: ";
    cin.getline(breed, 100);
    cin.ignore();
    cout << "Has the dog been vaccinated (1 = Yes/ 0 = No): ";
    cin >> vaccines;
}

person gaara    schedule 13.06.2019    source источник
comment
Создайте минимально воспроизводимый пример   -  person eerorika    schedule 13.06.2019
comment
std::getline(cin, breed); может быть полезно. en.cppreference.com/w/cpp/string/basic_string/getline   -  person Eljay    schedule 13.06.2019
comment
извините, ребята, я новичок в кодировании и новичок здесь. Я постарался упростить код из общей программы, и перепостил его выше. по-прежнему получает то же сообщение об ошибке, даже без классов и функций.   -  person gaara    schedule 13.06.2019
comment
Хорошо, то, что предложил Элджей, устранило сообщение об ошибке... но если в вводе есть пробел или белый символ, он все равно пропускает следующие строки кода. Я думал, что смысл getline в том, чтобы этого не произошло?   -  person gaara    schedule 13.06.2019
comment
ignore принадлежит после инструкций, которые оставляют данные в потоке, который вы хотите удалить. Не размещайте их перед другими инструкциями или случайным образом по всему коду на всякий случай.   -  person user4581301    schedule 13.06.2019


Ответы (1)


Во-первых, вам нужно знать, что в C++ есть две getline вещи: одна в области ввода-вывода и одна в стандартном пространстве имен верхнего уровня.

cin.getline(breed, 100) находится в области ввода-вывода (в частности, istream::getline(), и он ничего не знает о строках, предпочитая работать с символьными массивами. Вам, вероятно, следует избегать этого.

Тот, который действительно знает о строках, — это std::getline(), и это, как правило, предпочтительнее, если вы не хотите возвращаться к старым недобрым временам C-устаревших "строк".

Кроме того, вам нужно быть осторожным в C++, когда вы смешиваете операции ввода, зависящие от типа (например, <<), и операции ввода, зависящие от строки (например, getline). Важно знать, где находится указатель файла до и после каждой операции.

Например, cin << someInt оставит указатель файла сразу после считанного целого числа. Это означает, что если вашей следующей операцией будет getline(), она, скорее всего, найдет все в строке после этого целого числа (как минимум, это будет символ новой строки которую вы ввели для обработки целого числа), не следующая строка, в которой вы собираетесь вводить строку.

Простое исправление для вашего случая - игнорировать все, включая новую строку, прежде чем пытаться получить следующую строку. Это можно сделать с помощью ignore():

#include <iostream>
#include <string>
#include <limits>
using namespace std;

int main() {
    int birthyear; string breed; bool vaccines;

    cout << "Please enter value for dog's birth year: ";
    cin >> birthyear;

    cout << "What is the breed of the dog: ";
    cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
    getline(cin, breed);

    cout << "Has the dog been vaccinated (1 = Yes/ 0 = No): ";
    cin >> vaccines;

    // Output what you got.

    cout << birthyear << " '" << breed << "' " << vaccines << '\n';
}

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

Что-то вроде этого должно быть хорошим началом:

#include <iostream>
#include <string>
#include <limits>
#include <set>
#include <cstdlib>
using namespace std;

// Get string, always valid. Optionally strip leading and
// trailing white-space.

bool getResp(const string &prompt, string &val, bool strip = false) {
    cout << prompt;
    getline(cin, val);
    if (strip) {
        val.erase(0, val.find_first_not_of(" \t"));
        val.erase(val.find_last_not_of(" \t") + 1);
    }
    return true;
}

// Get unsigned, must ONLY have digits (other than
// leading or trailing space).

bool getResp(const string &prompt, unsigned long &val) {
    string str;
    if (! getResp(prompt, str, true)) return false;

    for (const char &ch: str)
        if (! isdigit(ch)) return false;

    val = strtoul(str.c_str(), nullptr, 10);
    return true;
}

// Get truth value (ignoring leading/trailing space),
// and allow multiple languages.

bool getResp(const string &prompt, bool &val) {
    string str;
    if (! getResp(prompt, str, true)) return false;

    const set<string> yes = {"yes", "y", "1", "si"};
    const set<string> no = {"no", "n", "0", "nyet"};

    if (yes.find(str) != yes.end()) {
        val = true;
        return true;
    }

    if (no.find(str) != no.end()) {
        val = false;
        return true;
    }

    return false;
}

// Test driver for your situation.

int main() {
    unsigned long birthYear;
    std::string dogBreed;
    bool isVaccinated;

    if (! getResp("What year was the dog born? ", birthYear)) {
        std::cout << "** ERROR, invalid value\n";
        return 1;
    }

    if (! getResp("What is the breed of the dog? ", dogBreed, true)) {
        std::cout << "** ERROR, invalid value\n";
        return 1;
    }

    if (! getResp("Has the dog been vaccinated? ", isVaccinated)) {
        std::cout << "** ERROR, invalid value\n";
        return 1;
    }

    std::cout
        << birthYear
        << " '" << dogBreed << "' "
        << (isVaccinated ? "yes" : "no") << '\n';
}
person paxdiablo    schedule 13.06.2019
comment
Как бы вы преобразовывали каждый из входных данных в переменную на основе строки и преобразовывали их после? Звучит полезно, но я все еще изучаю С++ и не совсем понимаю эту концепцию? - person gaara; 13.06.2019
comment
@gaara, смотри обновление. Я знаю, что вы все еще учитесь, и вам, возможно, придется кое-что переварить, но это стоит вашего времени. - person paxdiablo; 13.06.2019
comment
Большое спасибо! Я очень ценю помощь и информацию. Я взял часть вашего кода, и это помогло мне создать работающую программу. Тем не менее, вы можете помочь мне понять цель getResp? Чем он отличается/лучше, чем cin, так как я еще не сталкивался с ним? Мне очень нравится, как ваш код позволяет bool принимать в качестве допустимых ответов больше, чем просто 1 и 0. Есть ли другие способы выполнить ту же задачу с помощью переменной bool? Еще раз спасибо за вашу помощь! - person gaara; 14.06.2019
comment
@gaara, вы вряд ли сталкивались с этим, так как я только что только написал это :-) Причина getResp заключается в том, чтобы просто предоставить и перегрузить функцию, которая делает за вас большую часть тяжелой работы (вывод приглашение, получите входную строку и выполните любую проверку того, что было введено). Это освобождает ваш основной код, чтобы просто указать его намерение, а не иметь в нем много кода преобразования и/или проверки. - person paxdiablo; 15.06.2019