0 / 0 / 0 Регистрация: 16.07.2016 Сообщений: 23 |
|
1 |
|
26.07.2016, 13:00. Показов 8923. Ответов 12
Доброго времени суток
__________________
0 |
257 / 234 / 185 Регистрация: 02.04.2016 Сообщений: 898 |
|
26.07.2016, 13:05 |
2 |
Кидай сюда код.
1 |
Модератор 12641 / 10135 / 6102 Регистрация: 18.12.2011 Сообщений: 27,170 |
|
26.07.2016, 13:09 |
3 |
1 |
INSIDERS 0 / 0 / 0 Регистрация: 16.07.2016 Сообщений: 23 |
||||
26.07.2016, 13:51 [ТС] |
4 |
|||
код очень большой
0 |
Объявлятель переменных 1199 / 389 / 315 Регистрация: 24.09.2011 Сообщений: 1,232 |
|
26.07.2016, 14:03 |
5 |
Пробовали тот же код с использованием
1 |
0 / 0 / 0 Регистрация: 16.07.2016 Сообщений: 23 |
|
26.07.2016, 14:11 [ТС] |
6 |
ну со switch я не пробовал
0 |
257 / 234 / 185 Регистрация: 02.04.2016 Сообщений: 898 |
|
26.07.2016, 14:15 |
7 |
Значит вы не перезагрузили operator<< и пытаетесь его использовать наверное…
1 |
0 / 0 / 0 Регистрация: 16.07.2016 Сообщений: 23 |
|
26.07.2016, 14:33 [ТС] |
8 |
то есть если я скопирую весь код пересоздам проект это поможет ?
0 |
257 / 234 / 185 Регистрация: 02.04.2016 Сообщений: 898 |
|
26.07.2016, 14:39 |
9 |
INSIDERS, Тогда бы так делали все программисты..
1 |
Объявлятель переменных 1199 / 389 / 315 Регистрация: 24.09.2011 Сообщений: 1,232 |
|
26.07.2016, 14:48 |
10 |
ошибка появляется во время компиляции Я честно пытался найти в приведённом выше коде 493 строку, но не преуспел.
1 |
0 / 0 / 0 Регистрация: 16.07.2016 Сообщений: 23 |
|
26.07.2016, 15:14 [ТС] |
11 |
я не программист пока что не те знания Добавлено через 2 минуты Добавлено через 20 минут
0 |
16495 / 8988 / 2205 Регистрация: 30.01.2014 Сообщений: 15,611 |
|
26.07.2016, 16:17 |
12 |
INSIDERS, кавычки внутри строки надо экранировать.
1 |
SpBerkut Объявлятель переменных 1199 / 389 / 315 Регистрация: 24.09.2011 Сообщений: 1,232 |
||||
26.07.2016, 16:26 |
13 |
|||
Если синтаксис подсветить, то всё становится очевидным.
1 |
Содержание
- Ошибка компилятора C2065
- Идентификатор является необъявленным
- Пример: идентификатор с ошибками
- Пример. Использование несеченного идентификатора
- Пример: предварительно скомпилированные заголовки не первый
- Пример: отсутствующий файл заголовка
- Пример: отсутствует закрывающая цитата
- Пример. Использование итератора вне для области цикла
- Пример: объявление препроцессора удалено
- Пример: Сбой вычета типа C++/CLI
- Пример. Параметры атрибута C++/CLI
- 20.5 – Исключения, классы и наследование
- Исключения и функции-члены
- Когда конструкторы дают сбой
- Классы исключений
- Исключения и наследование
- std::exception
- Использование стандартных исключений напрямую
- Создание собственных классов, производных от std::exception или std::runtime_error
Ошибка компилятора C2065
Компилятор не может найти объявление для идентификатора. Эта ошибка имеет несколько возможных причин. Наиболее распространенные причины C2065 : идентификатор не был объявлен, идентификатор написан с ошибками, заголовок, в котором объявлен идентификатор, не включен в файл, или в идентификаторе отсутствует квалификатор области, например, cout вместо std::cout . Дополнительные сведения о объявлениях в C++ см. в разделе Объявления и определения (C++).
Ниже приведены некоторые распространенные проблемы и их решения.
Идентификатор является необъявленным
Если идентификатор является переменной или именем функции, его необходимо объявить, прежде чем его можно будет использовать. Объявление функции должно также включать типы ее параметров, прежде чем можно будет использовать функцию. Если переменная объявлена с помощью auto , компилятор должен иметь возможность определить тип из инициализатора.
Если идентификатор является членом класса или структуры или объявлен в пространстве имен, он должен быть квалифицирован по имени класса или структуры или имени пространства имен при использовании за пределами области структуры, класса или пространства имен. Кроме того, пространство имен должно быть передано в область с помощью using директивы, например using namespace std; , или имя члена должно быть передано в область с помощью using объявления, например using std::string; . В противном случае непроверенное имя считается необъявленным идентификатором в текущей области.
Если идентификатор является тегом для определяемого пользователем class типа, например или struct , тип тега необходимо объявить, прежде чем его можно будет использовать. Например, объявление struct SomeStruct < /*. */ >; должно существовать, прежде чем можно будет объявить переменную SomeStruct myStruct; в коде.
Если идентификатор является псевдонимом типа, тип должен быть объявлен объявлением using или typedef перед его использованием. Например, необходимо объявить using my_flags = std::ios_base::fmtflags; перед использованием my_flags в качестве псевдонима типа для std::ios_base::fmtflags .
Пример: идентификатор с ошибками
Эта ошибка обычно возникает, если имя идентификатора написано с ошибкой или идентификатор использует неправильные прописные и строчные буквы. Имя в объявлении должно точно соответствовать используемому имени.
Пример. Использование несеченного идентификатора
Эта ошибка может возникнуть, если область действия идентификатора не задана должным образом. Если при использовании cout отображается C2065 , причина заключается в проблеме области. Если функции и операторы стандартной библиотеки C++ не полностью определяются пространством имен или вы не включили std пространство имен в текущую using область с помощью директивы , компилятор не сможет найти их. Чтобы устранить эту проблему, необходимо либо полностью указать имена идентификаторов, либо указать пространство имен с помощью директивы using .
В этом примере не удается выполнить компиляцию, так как cout и endl определены в std пространстве имен:
Идентификаторы, объявленные в типах class , struct или enum class , также должны быть квалифицированы по имени включающей области при их использовании за пределами этой области.
Пример: предварительно скомпилированные заголовки не первый
Эта ошибка может возникнуть, если перед файлом предварительно скомпилированного файла заголовка были помещены директивы препроцессора, например #include , #define или #pragma . #include Если исходный файл использует предварительно скомпилированный файл заголовка (то есть, если он компилируется с помощью /Yu параметра компилятора), то все директивы препроцессора, предшествующие предварительно скомпилированному файлу заголовка, игнорируются.
В этом примере не удается выполнить компиляцию, так как cout и endl определены в заголовке , который игнорируется, так как он включен перед предварительно скомпилированным файлом заголовка. Чтобы выполнить сборку этого примера, создайте все три файла, затем скомпилируйте pch.h (в некоторых версиях Visual Studio используется stdafx.cpp ), а затем скомпилируйте C2065_pch.cpp .
Исходный pch.h файл или stdafx.h :
Исходный файл C2065_pch.cpp :
Чтобы устранить эту проблему, добавьте #include в файл предкомпилированного заголовка или переместите его после включения предварительно скомпилированного файла заголовка в исходный файл.
Пример: отсутствующий файл заголовка
Ошибка может возникнуть, если вы не включили файл заголовка, в который объявляется идентификатор. Убедитесь, что файл, содержащий объявление идентификатора, включен в каждый исходный файл, в котором он используется.
Другой возможной причиной является использование списка инициализаторов без включения заголовка .
Эта ошибка может возникнуть в исходных файлах классического приложения Для Windows, если вы определяете VC_EXTRALEAN , WIN32_LEAN_AND_MEAN или WIN32_EXTRA_LEAN . Эти макросы препроцессора исключают некоторые файлы заголовков из windows.h и afxv_w32.h для ускорения компиляции. Найдите в windows.h и afxv_w32.h актуальное описание того, что исключается.
Пример: отсутствует закрывающая цитата
Эта ошибка может возникнуть, если отсутствует закрывающая кавычка после строковой константы. Это простой способ запутать компилятор. Отсутствующие закрывающие кавычки могут находиться в нескольких строках перед сообщаемой ошибкой.
Пример. Использование итератора вне для области цикла
Эта ошибка может возникнуть, если объявить переменную итератора в for цикле, а затем попытаться использовать эту переменную итератора вне области for цикла. Компилятор включает параметр компилятора /Zc:forScope по умолчанию. Дополнительные сведения см. в разделе Поддержка итератора отладки.
Пример: объявление препроцессора удалено
Эта ошибка может возникнуть, если вы ссылаетесь на функцию или переменную, которая находится в условно скомпилированном коде, который не компилируется для текущей конфигурации. Эта ошибка также может возникнуть при вызове функции в файле заголовка, которая в настоящее время не поддерживается в среде сборки. Если определенные переменные или функции доступны только при определении определенного макроса препроцессора, убедитесь, что код, вызывающий эти функции, может быть скомпилирован только при определении того же макроса препроцессора. Эту проблему легко обнаружить в интегрированной среде разработки: объявление для функции неактивно, если необходимые макросы препроцессора не определены для текущей конфигурации сборки.
Ниже приведен пример кода, который работает при сборке в отладке, но не в выпуске:
Пример: Сбой вычета типа C++/CLI
Эта ошибка может возникнуть при вызове универсальной функции, если предполагаемый аргумент типа не может быть выведен из используемых параметров. Дополнительные сведения см. в разделе Универсальные функции (C++/CLI).
Пример. Параметры атрибута C++/CLI
Эта ошибка также может быть создана в результате работы компилятора по соответствунию, выполненной для Visual Studio 2005: проверка параметров для атрибутов Visual C++.
Источник
20.5 – Исключения, классы и наследование
Исключения и функции-члены
До этого момента в данном руководстве вы видели исключения, используемые только в функциях, не являющихся членами. Однако исключения также полезны в функциях-членах и тем более в перегруженных операторах. Рассмотрим следующий перегруженный оператор [] как часть простого класса целочисленного массива:
Хотя эта функция будет отлично работать, пока index является допустимым индексом массива, ей очень не хватает проверки на ошибку. Мы могли бы добавить инструкцию assert , чтобы убедиться, что index корректен:
Теперь, если пользователь передаст недопустимый индекс, программа вызовет ошибку утверждения. К сожалению, поскольку перегруженные операторы предъявляют особые требования к количеству и типу параметров, которые они могут принимать и возвращать, у них нет гибкости для передачи кодов ошибок или логических значений в вызывающую функцию для обработки. Однако, поскольку исключения не изменяют сигнатуру функции, они могут быть здесь очень полезны. Например:
Теперь, если пользователь передает недопустимый индекс, operator[] вызовет исключение типа int .
Когда конструкторы дают сбой
Конструкторы – это еще одна область классов, в которой исключения могут быть очень полезны. Если по какой-либо причине конструктор может дать сбой (например, пользователь передал недопустимые входные данные), просто выбросите исключение, чтобы указать, что объект не удалось создать. В таком случае создание объекта прерывается, и все члены класса (которые уже были созданы и инициализированы до выполнения тела конструктора) уничтожаются как обычно.
Однако деструктор класса в этом случае никогда не вызывается (потому что объект так и не завершил построение). Поскольку деструктор никогда не выполняется, вы не можете полагаться на этот деструктор в освобождении любых ресурсов, которые уже были выделены.
Это приводит к вопросу о том, что мы должны делать, если мы выделили ресурсы в нашем конструкторе, а затем возникает исключение до завершения конструктора. Как обеспечить правильное освобождение уже выделенных ресурсов? Один из способов – обернуть любой код, который может дать сбой в блок try , использовать соответствующий блок catch для перехвата исключения и выполнить любую необходимую очистку, а затем повторно выбросить исключение (эту тему мы обсудим в уроке «20.6 – Повторное выбрасывание исключений»). Однако это добавляет много бардака, и здесь легко ошибиться, особенно если ваш класс выделяет несколько ресурсов.
К счастью, есть способ получше. Воспользовавшись тем фактом, что члены класса уничтожаются, даже если конструктор завершается сбоем, если вы выполняете размещение ресурсов внутри членов класса (а не в самом конструкторе), эти члены, когда они уничтожаются, могут выполнять после себя очистку.
Этот код печатает:
В приведенной выше программе, когда класс A выдает исключение, все члены A уничтожаются. Вызывается деструктор m_member , который дает возможность освободить все выделенные им ресурсы.
Это одна из причин того, что RAII (метод, описанный в уроке «12.9 – Деструкторы») так широко пропагандируется – даже в исключительных обстоятельствах классы, реализующие RAII, могут выполнять после себя очистку.
Однако создание пользовательского класса, такого как Member , для управления размещением ресурсов неэффективно. К счастью, стандартная библиотека C++ поставляется с RAII-совместимыми классами для управления распространенными типами ресурсов, такими как файлы ( std::fstream , рассмотренные в уроке «23.6 – Основы файлового ввода/вывода») и динамическая память ( std::unique_ptr и другие умные указатели, описанные в «M.1 – Введение в умные указатели и семантику перемещения»).
Например, вместо этого:
В первом случае, если конструктор Foo завершится со сбоем после того, как ptr выделил свою динамическую память, Foo будет отвечать за очистку, что может быть сложной задачей. Во втором случае, если конструктор Foo завершится со сбоем после того, как ptr выделил свою динамическую память, деструктор ptr выполнит и вернет эту память в систему. Foo не должен выполнять какую-либо явную очистку, когда обработка ресурсов делегируется членам, совместимым с RAII!
Классы исключений
Одна из основных проблем с использованием базовых типов данных (таких как int ) в качестве типов исключений заключается в том, что они по своей сути непонятны. Еще бо́льшая проблема – это разрешение неоднозначности того, что означает исключение, когда в блоке try есть несколько инструкций или вызовов функций.
В этом примере, если бы мы перехватили исключение типа int , о чем это нам сказало бы? Был ли один из индексов массива вне допустимого диапазона? operator+ вызвал целочисленное переполнение? Сбой оператора new из-за нехватки памяти? К сожалению, в этом случае нет простого способа устранить неоднозначность. Хотя мы можем генерировать исключения const char* для решения проблемы определения, ЧТО пошло не так, это всё же не дает нам возможности обрабатывать исключения из разных источников по-разному.
Один из способов решить эту проблему – использовать классы исключений. Класс исключения – это просто обычный класс, специально созданный для выдачи исключения. Давайте спроектируем простой класс исключения, который будет использоваться с нашим классом IntArray :
Вот полный код программы, использующей этот класс:
Используя такой класс, мы можем сделать так, чтобы исключение вернуло описание возникшей проблемы, которое предоставляет контекст для того, что пошло не так. А поскольку ArrayException – это собственный уникальный тип, мы можем специально перехватывать исключения, создаваемые классом массива, и при желании обрабатывать их иначе, чем другие исключения.
Обратите внимание, что обработчики исключений должны перехватывать объекты класса исключения по ссылке, а не по значению. Это предотвращает создание компилятором копии исключения, что может быть дорогостоящим, если исключение является объектом класса, и предотвращает обрезку объекта при работе с производными классами исключений (о которых мы поговорим чуть позже). Как правило, следует избегать перехвата исключений по указателю, если для этого нет особых причин.
Исключения и наследование
Поскольку можно выбрасывать объекты классов, в качестве исключений, а классы могут быть производными от других классов, нам необходимо учитывать, что происходит, когда в качестве исключений мы используем наследованные классы. Оказывается, обработчики исключений будут не только соответствовать классам определенного типа, они также будут соответствовать классам, производным от этого конкретного типа! Рассмотрим следующий пример:
В приведенном выше примере мы генерируем исключение типа Derived . Однако результат этой программы:
Во-первых, как упоминалось выше, производные классы будут перехвачены обработчиками базового типа. Поскольку Derived является производным от Base , Derived «является» Base (между ними есть связь «является чем-либо»). Во-вторых, когда C++ пытается найти обработчик возникшего исключения, он делает это последовательно. Следовательно, первое, что делает C++, – это проверяет, соответствует ли обработчик исключений для Base исключению Derived . Поскольку Derived «является» Base , ответ – да, и он выполняет блок catch для типа Base ! Блок catch для Derived в этом случае даже не проверяется.
Чтобы этот пример работал, как задумывалось, нам нужно изменить порядок блоков catch :
Таким образом, обработчик Derived получит первым шанс перехватить объекты типа Derived (до того, как это сделает обработчик для Base ). Объекты типа Base не будут соответствовать обработчику Derived ( Derived «является» Base , но Base не является Derived ) и, таким образом, «провалятся вниз» до обработчика Base .
Правило
Обработчики для исключений производных классов должны быть идти перед обработчиками для базовых классов.
Возможность использовать обработчик для перехвата исключений производных типов с помощью обработчика для базового класса может быть чрезвычайно полезной.
std::exception
Многие классы и операторы в стандартной библиотеке в случае сбоя выдают исключения с объектами классов. Например, оператор new может выбросить std::bad_alloc , если не может выделить достаточно памяти. Неудачный dynamic_cast вызовет std::bad_cast . И так далее. Начиная с C++20, существует 28 различных классов исключений, которые могут быть сгенерированы, и в каждом последующем стандарте языка добавляется еще больше.
Хорошая новость заключается в том, что все эти классы исключений являются производными от одного класса std::exception . std::exception – это небольшой интерфейсный класс, предназначенный для использования в качестве базового класса для любого исключения, создаваемого стандартной библиотекой C++.
В большинстве случаев, когда стандартная библиотека генерирует исключение, нас не волнует, неудачное ли это выделение памяти, неправильное приведение или что-то еще. Нас просто волнует, что что-то катастрофически пошло не так, и теперь наша программа дает сбой. Благодаря std::exception мы можем настроить обработчик исключений для перехвата исключений типа std::exception , и в итоге мы перехватим и std::exception , и все производные исключения в одном месте. Всё просто!
Приведенная выше программа печатает:
Приведенный выше пример довольно простой. В нем стоит отметить одну вещь: std::exception имеет виртуальную функцию-член what() , которая возвращает строку в стиле C с описанием исключения. Большинство производных классов переопределяют функцию what() для изменения этого сообщения. Обратите внимание, что эта строка предназначена для использования только для описательного текста – не используйте ее для сравнений, поскольку не гарантируется, что она будет одинаковой для разных компиляторов.
Иногда нам нужно обрабатывать определенный тип исключения по-другому. В этом случае мы можем добавить обработчик для этого конкретного типа и позволить всем остальным «проваливаться вниз» до обработчика базового типа. Рассмотрим следующий код:
В этом примере исключения типа std::length_error будут перехвачены и обработаны первым обработчиком. Исключения типа std::exception и всех других производных классов будут перехвачены вторым обработчиком.
Такие иерархии наследования позволяют нам использовать определенные обработчики для нацеливания на определенные производные классы исключений или использовать обработчики базовых классов для перехвата всей иерархии исключений. Это позволяет нам точно контролировать, какие исключения мы хотим обрабатывать, и при этом нам не нужно делать слишком много работы, чтобы отловить «всё остальное» в иерархии.
Использование стандартных исключений напрямую
Ничто напрямую не вызывает std::exception , и вы тоже. Однако вы можете свободно использовать другие стандартные классы исключений из стандартной библиотеки, если они адекватно соответствуют вашим потребностям. Список всех стандартных исключений вы можете найти на cppreference.
std::runtime_error (включен как часть заголовка stdexcept ) выбирается часто потому, что он имеет обобщенное название, а его конструктор принимает настраиваемое сообщение:
Этот код печатает:
Создание собственных классов, производных от std::exception или std::runtime_error
Конечно, вы можете наследовать свои классы от std::exception и переопределять виртуальную константную функцию-член what() . Вот та же программа, что и выше, но с исключением ArrayException , производным от std::exception :
Обратите внимание, что виртуальная функция what() имеет спецификатор noexcept (что означает, что эта функция обещает не генерировать исключения). Следовательно, у нашего переопределения также должен быть спецификатор noexcept .
Поскольку std::runtime_error уже имеет возможности обработки строк, он также популярен в качестве базового класса для производных классов исключений. Вот тот же пример, использующий std::runtime_error :
Вам решать, хотите ли вы создать свои собственные автономные классы исключений, использовать стандартные классы исключений или наследовать свои классы исключений от std::exception или std::runtime_error . Все эти подходы допустимы и зависят от ваших целей.
Источник
Я изучаю шаблоны C ++, и у меня есть функция для различных типов карт:
template<typename T> void foo(T m1, T m2){ //map m1 and map m2
map<pair<T, int>, int>::iterator itr1 = m1.begin();
map<pair<T, int>, int>::iterator itr2 = m2.begin();
while (itr1 != m1.end() && itr2 != m2.end()){
//do something with itr1 and itr2
}
}
Когда я компилирую его в VS2013, я получил ошибку: error C2088: '!=' : illegal for class
что указывает на while (itr1 != m1.end() && itr2 != m2.end())
, Но если я явно объявляю тип карт (то есть не использую шаблон), у меня нет ошибки. Кто-нибудь может сказать мне, что я здесь делаю не так? Спасибо!
-3
Решение
std::map<pair<T, int>, int>::iterator
является итератором с карты, тип ключа которого pair<T, int>
(где T
по-видимому, также map
в вашем примере) и какой тип значения int
, который явно отличается от typename T::iterator
который является типом m1.begin()
, Что вы, вероятно, хотите, это:
template<typename T>
void foo(T m1, T m2) {
typename T::iterator itr1 = m1.begin();
/* ... */
}
Или же:
template <typename T>
void foo(std::map<std::pair<T, int>, int> m1,
std::map<std::pair<T, int>, int> m2) {
typename T::iterator itr1 = m1.begin();
/* ... */
}
В первом случае параметр шаблона является типом map
(T = std::map<std::pair<T, int>>
) в то время как во втором случае это тип первого атрибута ключа карты.
2
Другие решения
Других решений пока нет …
Here is my code where I try to access an element of class Edge
:
#include <iostream>
// for the sort()
#include <algorithm>
#define PI 3.14159265358979323846
struct Point{
Point(int xx, int yy): x(xx), y(yy) { }
int x;
int y;
};
// class Edge: representing lines segments of the poly-line
struct Edge{
// constructor
Edge(Point p0, Point p1) : start(p0), end(p1){
if (p0.x == p1.x && p0.y == p1.y) throw std::invalid_argument("Edge: Identical points!");
}
// operator< defined for the sorting by increasing ordinate of the end point
bool operator<(const Edge& e){ return (end.y < e.end.y); }
// data members: start point and end point of the line
Point start;
Point end;
};
static void generatePoints(vector<Point>& p){
p.push_back(Point(50,50));
p.push_back(Point(200,50));
p.push_back(Point(200,200));
p.push_back(Point(50,200));
}
//------------------------------------------------------------------------------------------------
int main(){
// Generate points for the poly-line
vector<Point> polyPoints;
generatePoints(polyPoints);
vector<Edge> polyEdges;
Point first = polyPoints(0);
Point last = polyPoints(polyPoints.size()-1);
polyEdges.push_back(Edge(last, first));
for (size_t i = 1; i < polyPoints.size(); ++i) polyEdges.push_back(Edge(polyPoints[i-1], polyPoints[i]));
int yCoordinate = polyEdges[i].end.y;
return 0;
}
Now, I have a vector of edges, like so:
vector<Edge> polyEdges;
and when I try to access it a specific member polyEdges[i].end.y
, I get the following error message:
'vector' : undeclared identifier
'Point' : illegal use of this type as an expression
see declaration of 'Point'
'p' : undeclared identifier
'generatePoints' : function-style initializer appears to be a function definition
vector' : undeclared identifier
see declaration of 'Point'
'polyPoints' : undeclared identifier
'Point' : illegal use of this type as an expression
'polyPoints' : undeclared identifier
'generatePoints': identifier not found
'vector' : undeclared identifier
Edge' : illegal use of this type as an expression
see declaration of 'Edge'
error C2088: '[' : illegal for class
polyEdges' : undeclared identifier
'polyPoints': identifier not found
'polyPoints' : undeclared identifier
left of '.size' must have class/struct/union
'Point' : illegal use of this type as an expression
error C2228: left of '.end' must have class/struct/union
error C2228: left of '.y' must have class/struct/union
It must be related with the overloading of the []operator
.
Question:
Should I overload [] operator
and if so, how to do it?
Here is my code where I try to access an element of class Edge
:
#include <iostream>
// for the sort()
#include <algorithm>
#define PI 3.14159265358979323846
struct Point{
Point(int xx, int yy): x(xx), y(yy) { }
int x;
int y;
};
// class Edge: representing lines segments of the poly-line
struct Edge{
// constructor
Edge(Point p0, Point p1) : start(p0), end(p1){
if (p0.x == p1.x && p0.y == p1.y) throw std::invalid_argument("Edge: Identical points!");
}
// operator< defined for the sorting by increasing ordinate of the end point
bool operator<(const Edge& e){ return (end.y < e.end.y); }
// data members: start point and end point of the line
Point start;
Point end;
};
static void generatePoints(vector<Point>& p){
p.push_back(Point(50,50));
p.push_back(Point(200,50));
p.push_back(Point(200,200));
p.push_back(Point(50,200));
}
//------------------------------------------------------------------------------------------------
int main(){
// Generate points for the poly-line
vector<Point> polyPoints;
generatePoints(polyPoints);
vector<Edge> polyEdges;
Point first = polyPoints(0);
Point last = polyPoints(polyPoints.size()-1);
polyEdges.push_back(Edge(last, first));
for (size_t i = 1; i < polyPoints.size(); ++i) polyEdges.push_back(Edge(polyPoints[i-1], polyPoints[i]));
int yCoordinate = polyEdges[i].end.y;
return 0;
}
Now, I have a vector of edges, like so:
vector<Edge> polyEdges;
and when I try to access it a specific member polyEdges[i].end.y
, I get the following error message:
'vector' : undeclared identifier
'Point' : illegal use of this type as an expression
see declaration of 'Point'
'p' : undeclared identifier
'generatePoints' : function-style initializer appears to be a function definition
vector' : undeclared identifier
see declaration of 'Point'
'polyPoints' : undeclared identifier
'Point' : illegal use of this type as an expression
'polyPoints' : undeclared identifier
'generatePoints': identifier not found
'vector' : undeclared identifier
Edge' : illegal use of this type as an expression
see declaration of 'Edge'
error C2088: '[' : illegal for class
polyEdges' : undeclared identifier
'polyPoints': identifier not found
'polyPoints' : undeclared identifier
left of '.size' must have class/struct/union
'Point' : illegal use of this type as an expression
error C2228: left of '.end' must have class/struct/union
error C2228: left of '.y' must have class/struct/union
It must be related with the overloading of the []operator
.
Question:
Should I overload [] operator
and if so, how to do it?
Итак, я только начинаю нелегкий путь в C++, так что решил сделать несложную программу: выдача вопросов и счет баллов за них. В суть углубляться не буду, но идея работы программы такая: в подключаемом файле я создаю и инициализирую двумерный вектор, каждый элемент которого строка с вопросом, так же я храню кол-во тем. Сейчас для примера будет 1 тема, но это не важно. Важно то, что при попытке сделать это получаю каскад ошибок, и вопрос: что я делаю не так и как это сделать лучше?
Код:
#ifndef QPACK1_H
#define QPACK1_H
int theme_amount = 1;
std::vector<std::vector<std::string> > questions(theme_amount + 1, std::vector<std::string>(6, " "));
questions[1][0] = "Вы попали на тему: Name of the themen" ; // сначала номер темы, потом номер вопроса(по 5), 0 вопрос - название темы.
questions[1][1] = "Question 1";
questions[1][2] = "Question 2";
questions[1][3] = "Question 3";
questions[1][4] = "Question 4";
questions[1][5] = "Question 5";
#endif
Список ошибок:
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(8,1): error C2466: невозможно выделить память для массива постоянного нулевого размера
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(8,17): error C2087: questions: отсутствует индекс
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(8,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(10,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(10,1): error C2040: questions: "int [1][1]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(11,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(11,1): error C2040: questions: "int [1][2]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(12,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(12,1): error C2040: questions: "int [1][3]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(13,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(13,1): error C2040: questions: "int [1][4]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(14,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(14,1): error C2040: questions: "int [1][5]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2CHGK_game.cpp(44,52): error C2088: [: недопустимо для class
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2CHGK_game.cpp(46,48): error C2088: [: недопустимо для class
Основной код программы:
#include <vector>
#include <iostream>
#include <string>
#include "qpack1.h" //список вопросов
struct players
{
std::vector<std::string> name;
std::vector<int> score;
};
int main()
{
int pl_amount, qst_number = 0;
players plist;
std::string input;
std::cout << "Enter number of players(less then 10): ";
std::cin >> pl_amount;
plist.name.resize(pl_amount);
plist.score.resize(pl_amount);
plist.score.assign(plist.score.size(), 0);
std::cout << "Enter players names: n";
for (int i = 0; i < pl_amount; i++)
std::cin >> plist.name[i];
std::cout << "Tips: enter stop to left the game. nUse + or - and number of player to give(take out) points to his score.n";
for (int theme_number = 1; theme_number <= theme_amount; theme_number++)
{
while (qst_number <= 4)
{
qst_number++;
if (qst_number == 1)
std::cout << questions[theme_number][0] << "n";
std::cout << questions[theme_number][qst_number] << "n";
TryAgain:
getline(std::cin, input);
if (input == "stop")
goto Results;
if(input.size() != 2 || !(input[1] > '0' && input[1] <= '9'))
{
std::cout << "Incorrect input.n";
goto TryAgain;
}
if(input[1] - '0' > pl_amount || input[1] - '0' <= 0)
{
std::cout << "Incorrect input(Player was not found).n";
goto TryAgain;
}
if (input[0] == '+')
{
plist.score[input[1] - '0' - 1] += qst_number * 10;
std::cout << plist.name[input[1] - '0' - 1] << " Gets + " << qst_number * 10 << " points!n";
}
else
if (input[0] == '-')
{
plist.score[input[1] - '0' - 1] -= qst_number * 10;
std::cout << plist.name[input[1] - '0' - 1] << " Gets - " << qst_number * 10 << " points!n";
}
else { std::cout << "Please start input with + or -.n";goto TryAgain; }
}
qst_number = 0;
}
Results:
std::cout << "The final score is: n";
for (int j = 0; j < pl_amount; j++)
std::cout << plist.name[j] << " : " << plist.score[j] << " points. n";
}
И еще есть проблема: при первом выводе темы и вопроса, сразу же после этого выводится Incorrect input, хотя ничего не было введено. (проверял заккоментив эту часть: )
questions[1][0] = «Вы попали на тему: Name of the themen» ; //
сначала номер темы, потом номер вопроса(по 5), 0 вопрос — название
темы.questions[1][1] = "Question 1"; questions[1][2] = "Question 2"; questions[1][3] = "Question 3"; questions[1][4] = "Question 4"; questions[1][5] = "Question 5";
В общем, как фиксить?)
Итак, я только начинаю нелегкий путь в C++, так что решил сделать несложную программу: выдача вопросов и счет баллов за них. В суть углубляться не буду, но идея работы программы такая: в подключаемом файле я создаю и инициализирую двумерный вектор, каждый элемент которого строка с вопросом, так же я храню кол-во тем. Сейчас для примера будет 1 тема, но это не важно. Важно то, что при попытке сделать это получаю каскад ошибок, и вопрос: что я делаю не так и как это сделать лучше?
Код:
#ifndef QPACK1_H
#define QPACK1_H
int theme_amount = 1;
std::vector<std::vector<std::string> > questions(theme_amount + 1, std::vector<std::string>(6, " "));
questions[1][0] = "Вы попали на тему: Name of the themen" ; // сначала номер темы, потом номер вопроса(по 5), 0 вопрос - название темы.
questions[1][1] = "Question 1";
questions[1][2] = "Question 2";
questions[1][3] = "Question 3";
questions[1][4] = "Question 4";
questions[1][5] = "Question 5";
#endif
Список ошибок:
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(8,1): error C2466: невозможно выделить память для массива постоянного нулевого размера
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(8,17): error C2087: questions: отсутствует индекс
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(8,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(10,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(10,1): error C2040: questions: "int [1][1]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(11,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(11,1): error C2040: questions: "int [1][2]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(12,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(12,1): error C2040: questions: "int [1][3]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(13,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(13,1): error C2040: questions: "int [1][4]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(14,19): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2qpack1.h(14,1): error C2040: questions: "int [1][5]" отличается по уровням косвенного обращения от "std::vector<std::vector<std::string,std::allocator<std::string>>,std::allocator<std::vector<std::string,std::allocator<std::string>>>>"
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2CHGK_game.cpp(44,52): error C2088: [: недопустимо для class
1>C:UsersUsersourcereposConsoleApplication2ConsoleApplication2CHGK_game.cpp(46,48): error C2088: [: недопустимо для class
Основной код программы:
#include <vector>
#include <iostream>
#include <string>
#include "qpack1.h" //список вопросов
struct players
{
std::vector<std::string> name;
std::vector<int> score;
};
int main()
{
int pl_amount, qst_number = 0;
players plist;
std::string input;
std::cout << "Enter number of players(less then 10): ";
std::cin >> pl_amount;
plist.name.resize(pl_amount);
plist.score.resize(pl_amount);
plist.score.assign(plist.score.size(), 0);
std::cout << "Enter players names: n";
for (int i = 0; i < pl_amount; i++)
std::cin >> plist.name[i];
std::cout << "Tips: enter stop to left the game. nUse + or - and number of player to give(take out) points to his score.n";
for (int theme_number = 1; theme_number <= theme_amount; theme_number++)
{
while (qst_number <= 4)
{
qst_number++;
if (qst_number == 1)
std::cout << questions[theme_number][0] << "n";
std::cout << questions[theme_number][qst_number] << "n";
TryAgain:
getline(std::cin, input);
if (input == "stop")
goto Results;
if(input.size() != 2 || !(input[1] > '0' && input[1] <= '9'))
{
std::cout << "Incorrect input.n";
goto TryAgain;
}
if(input[1] - '0' > pl_amount || input[1] - '0' <= 0)
{
std::cout << "Incorrect input(Player was not found).n";
goto TryAgain;
}
if (input[0] == '+')
{
plist.score[input[1] - '0' - 1] += qst_number * 10;
std::cout << plist.name[input[1] - '0' - 1] << " Gets + " << qst_number * 10 << " points!n";
}
else
if (input[0] == '-')
{
plist.score[input[1] - '0' - 1] -= qst_number * 10;
std::cout << plist.name[input[1] - '0' - 1] << " Gets - " << qst_number * 10 << " points!n";
}
else { std::cout << "Please start input with + or -.n";goto TryAgain; }
}
qst_number = 0;
}
Results:
std::cout << "The final score is: n";
for (int j = 0; j < pl_amount; j++)
std::cout << plist.name[j] << " : " << plist.score[j] << " points. n";
}
И еще есть проблема: при первом выводе темы и вопроса, сразу же после этого выводится Incorrect input, хотя ничего не было введено. (проверял заккоментив эту часть: )
questions[1][0] = «Вы попали на тему: Name of the themen» ; //
сначала номер темы, потом номер вопроса(по 5), 0 вопрос — название
темы.questions[1][1] = "Question 1"; questions[1][2] = "Question 2"; questions[1][3] = "Question 3"; questions[1][4] = "Question 4"; questions[1][5] = "Question 5";
В общем, как фиксить?)
Hi I am getting error C2088: ‘+=’: illegal for union error on visual studio …
for
same code working properly on gcc.
Could you please let me know the solution to fix this issue in c with visual studio.
typedef union {
float sm[8];
} Su;
typedef union {
Su v;
float bm[8];
} Bu;
int main() {
Bu A1, A2;
A2.v.sm[0] = 12.5;
// .... some assignments here
A1.v += A2.v; // <<<<<<<<<<<< error here
return 0;
}
rioV8
21.8k3 gold badges24 silver badges43 bronze badges
asked Apr 29, 2020 at 11:22
6
The v
member of A1
and A2
is a union type with a single array member sm
, and +=
is not defined for union types. If you want to add the values of A2.v.sm
to the values of A1.v.sm
, then you’ll need to use a loop:
for ( size_t i = 0; i < 8; i++ )
A1.v.sm[i] += A2.v.sm[i];
Edit
Chapter and verse:
6.5.16.2 Compound assignment
Constraints
1 For the operators
+=
and-=
only, either the left operand shall be an atomic, qualified, or
unqualified pointer to a complete object type, and the right shall have integer type; or the
left operand shall have atomic, qualified, or unqualified arithmetic type, and the right
shall have arithmetic type.
answered Apr 29, 2020 at 11:57
John BodeJohn Bode
117k18 gold badges116 silver badges194 bronze badges
Hi I am getting error C2088: ‘+=’: illegal for union error on visual studio …
for
same code working properly on gcc.
Could you please let me know the solution to fix this issue in c with visual studio.
typedef union {
float sm[8];
} Su;
typedef union {
Su v;
float bm[8];
} Bu;
int main() {
Bu A1, A2;
A2.v.sm[0] = 12.5;
// .... some assignments here
A1.v += A2.v; // <<<<<<<<<<<< error here
return 0;
}
rioV8
21.8k3 gold badges24 silver badges43 bronze badges
asked Apr 29, 2020 at 11:22
6
The v
member of A1
and A2
is a union type with a single array member sm
, and +=
is not defined for union types. If you want to add the values of A2.v.sm
to the values of A1.v.sm
, then you’ll need to use a loop:
for ( size_t i = 0; i < 8; i++ )
A1.v.sm[i] += A2.v.sm[i];
Edit
Chapter and verse:
6.5.16.2 Compound assignment
Constraints
1 For the operators
+=
and-=
only, either the left operand shall be an atomic, qualified, or
unqualified pointer to a complete object type, and the right shall have integer type; or the
left operand shall have atomic, qualified, or unqualified arithmetic type, and the right
shall have arithmetic type.
answered Apr 29, 2020 at 11:57
John BodeJohn Bode
117k18 gold badges116 silver badges194 bronze badges