Немного дополненный код из книги. Не знаю, почему выдаёт ошибку и, что самое удивительное, выдаёт ошибку не в мной написанном коде!
#include <iostream>
using namespace std;
char* mycpy(char* word_1, const char* word_2) {
while (*word_1++ = *word_2++);
return word_1;
}
class TwoDShape {
double width, height;
char name[20];
public:
TwoDShape() {
width = height = 0, 0;
mycpy(name, "no");
}
TwoDShape(double w, double h, const char* n) {
width = w;
height = h;
mycpy(name, n);
}
TwoDShape(double x, const char* n) {
width = height = x;
mycpy(name, n);
}
void showDim() {
cout << "Ширина и высота составляют " << width << "и " << height << "n";
}
double getWidth() { return width; }
double getHeight() { return height; }
void setWigth(double w) { width = w; }
void setHeight(double h) { height = h; }
void setName(const char* n) { mycpy(name, n); }
char* getName() { return name; }
virtual double area() = 0;
};
class Triangle : public TwoDShape {
char style[20];
public:
Triangle() {
mycpy(style, "no");
}
Triangle(const char* str, double w, double h) : TwoDShape(w, h, "треугольник") {
mycpy(style, str);
}
Triangle(double x) : TwoDShape(x, "треугольник") {
mycpy(style, "равнобедренный");
}
void showStyle() {
cout << "Треугольник " << style << "n";
}
double area() {
return getWidth() * getHeight() / 2;
}
};
class Rectangle : public TwoDShape {
public:
Rectangle(double w, double h) : TwoDShape(w, h, "Прямоугольник"){ }
Rectangle(double x) : TwoDShape(x, "Прямоугольник") { }
bool isSquare() {
if (getWidth() == getHeight()) return true;
return false;
}
double area() {
return getWidth() * getHeight();
}
};
class Circle : public TwoDShape {
double R;
public:
Circle(double r) : TwoDShape() {
R = r;
setName("Кргу");
}
double area() {
return (3.14 * (R * R));
}
};
int main() {
setlocale(LC_ALL, "ru");
TwoDShape* p_shapes[5];
p_shapes[0] = &Triangle("Прямоугольный", 8.0, 12.0); // <------------ Ошибка
p_shapes[1] = &Rectangle(10);// <------------ Ошибка
p_shapes[2] = &Rectangle(10, 4);// <------------ Ошибка
p_shapes[3] = &Triangle(7.0);// <------------ Ошибка
p_shapes[4] = &Circle(33.0);// <------------ Ошибка
for (int i = 0; i < 4; i++) {
cout << "Объект представляет собой " << p_shapes[i]->getName() << "n";
cout << "Площадь равна " << p_shapes[i]->area() << "n";
cout << "n";
}
}
мне было интересно, почему следующий код (уже закомментированы) вызоветC2102: '&' requires l-value
есть ли лучший способ, чтобы избежать использования tmp
переменной?
class a {
private:
int *dummy;
public:
int* get_dummy() const {
return dummy;
}
};
int main()
{
a aa;
// error C2102: '&' requires l-value
//int** me = &(aa.get_dummy());
// OK!
int *tmp = aa.get_dummy();
int** me = &(tmp);
}
5 ответов
, потому что a::get_dummy()
возвращает безымянный временный объект (указатель int).
Объект, возвращаемый функцией сидеть на вершине кадра стека и бессмысленно получать его адрес, так как это может быть недопустимо после окончания выражения.
вместо этого вы можете определить:
int **get_dummy() ... return &dummy;
вы можете думать о R-значении как о выражении, по существу, тогда как l-значение является фактическим объектом. У выражений нет адресов, и даже если бы они были, трудно представить, какой хороший адрес был бы. Легко понять, как адрес объекта может быть полезным.
немного сложно понять такую проблему абстрактно. Самый лучший способ развить понимание указателей и скомпилированных языков это изучение языка ассемблера.
нет.
какой адрес будет me
содержать иное? Вот вы дали ему адрес tmp
— но если вы замените его с int** me = &aa.get_dummy();
, куда она указывала?
на этот вопрос нет значимого ответа, поэтому стандарт требует, чтобы аргумент &
будьте lvalue.
на &
оператор должен быть применен к lvalue. Когда вызов aa.get_dummy()
не присваивается переменной, ее возвращаемое значение помещается только в стек, поэтому было бы глупо (и ошибочно) получить адрес элемента стека.
компилятор прав, согласно ISO C++ 5.3.1.3§:
результатом унарного оператора & является указатель на его операнд. Этот
операнд должен быть lvalue или квалифицированным id.
другими словами, вы можете взять адрес всего, что имя.
значения, возвращаемые из функции по стоимости не имеют имени и часто возвращаются через зарегистрироваться. Так что нет никакого»адрес » говорить о том, как значение не находится в памяти!
можно утверждать, что компилятор может быть умнее, обнаружить это и сохранить значение в стеке на время выражения, в котором используется адрес. Но это подвержено ошибкам (вы можете «утечь» указатель за пределы выражения) и, очевидно, будет расширение стандарта (т. е. не гарантируется совместимость). Так индекса MSVC просто запрещает.
увлекательно, компилятор is что умный когда дело доходит до ссылка к rvalue. Но нет такой функции указатель к rvalue.
чтобы ответить на ваш вопрос: попробуйте свести к минимуму взятие адресов вещей; взятие адреса переменной предотвращает оптимизатор от ввода его в регистр.
Но если вам нужно, верните ссылку вместо этого:
class a {
private:
int dummy;
public:
int get_dummy() const {
return dummy;
}
int& get_dummy() {
return dummy;
}
};
int main()
{
a aa;
int* me = &(aa.get_dummy());
}
обратите внимание, что имея const get_dummy()
строго не требуется, но поможет оптимизатору в контекстах rvalue.
Вопрос:
Я создаю консольное приложение в С++ с большим количеством меню и подменю. То, как я показываю свое меню, – это цикл do-while. Я создал функцию для отображения цикла меню с тремя параметрами – сначала это целое число, которое относится к количеству опций в меню, второе – функция, отображающая меню, а третья – другая функция, которая выполняет выбор, введенный пользователем.
class Menu {
public:
void displayInitialMenu(){
system("cls");
string menu = "nttXXXXXXXXX"
"nn Please select from the following:"
"nn 1. XXXXXXX"
"nn 2. XXXXXXX"
"nn 3. Exitn";
cout << menu << endl;
}
static bool checkOption (int option, int lower, int upper){
if ((option < lower) || (option > upper)){
return false;
} else {
return true;
}
}
static int readOption(int lower, int upper){
int option = 0;
bool validMenuOption = false;
do{
std::cin >> option;
validMenuOption = checkOption(option, lower, upper);
if (!validMenuOption){
std::cout << "nError: Input must be between " << lower;
std::cout << " and " << upper << "n" << std::endl;
}
} while (!validMenuOption);
return option;
}
};
Menu menu;
void menuLoop(int numberOfOptions, void (*displayMenu)(), void (*switchStatement)()){
int menuOption = numberOfOptions;
do {
(*displayMenu)();
menuOption = menu.readOption(1, numberOfOptions);
(*switchStatement)();
} while (menuOption != numberOfOptions);
}
static void performSelectionInitialMenu(int option){
switch (option){
case 1:
break;
case 2:
break;
case 3:
break;
default:
break;
}
}
int main()
{
/*
int menuOption = 3;
do {
menu.displayInitialMenu();
menuOption = menu.readOption(1, 3);
performSelectionInitialMenu(menuOption);
} while (menuOption != 3);
*/
menuLoop(3, &menu.displayInitialMenu(), &performSelectionInitialMenu(3));
return 0;
}
Ошибка, которую я получаю, является ошибкой “C2102: ‘&’ требуется l-значение” . Я несколько новичок в программировании, и это первый раз, когда я передаю функцию в качестве параметра. Я делаю эту функцию для устранения кода, который я прокомментировал. Может ли кто-нибудь указать, где я ошибаюсь, и возможное решение. Если нет, я просто использую дубликат кода для каждого меню, которое, как я знаю, плохое программирование.
Лучший ответ:
Вы пытаетесь взять адреса значений, возвращаемых функциями displayInitialMenu
и performSelectionInitialMenu
, но обе эти функции ничего не возвращают (void
). Удалите &
перед обеими вызовами, чтобы исправить эту конкретную проблему.
Ответ №1
Обычно вы вызываете его только так:
menuLoop(3, menu.displayInitialMenu, performSelectionInitialMenu);
просто имя, никаких параметров.
Однако performSelectionInitialMenu
:
static void performSelectionInitialMenu(int option)
Таким образом, он не соответствует сигнатуре указателя:
void (*switchStatement)()
что означает, что они несовместимы.
Ответ №2
Прежде всего, как только вы положите скобки после имени функции, вы больше не говорите о самой функции. i.e для бесплатных функций (функций, которые не являются членами класса) func
относится к адресу функции func
, тогда как func()
относится к тому, что возвращается из этой функции.
У вас есть еще одна проблема. Вы пытаетесь передать нестационарную функцию-член класса как свободную функцию. Это не является законным в С++, поскольку нестатические функции-члены имеют скрытый аргумент, а именно объект, на который он ссылается. Хотя теоретически object.memberfunc
может ссылаться на делегат, который при вызове вызывает memberfunc
on object
, он не находится в С++. Как обычно в С++, существует примерно один миллиард способов получить этот эффект с миллиардом компромиссов по различным критериям.
Я думаю, для вас проще всего использовать boost.bind. Итак, что вы пытаетесь сделать, будет выглядеть так:
#include<boost/bind.hpp>
using namespace boost;
...
template <class Functional>
void menuLoop(int numberOfOptions, Funcional displayMenu, void (*switchStatement)()){
...
menuLoop(3, bind(Menu::displayInitialMenu,menu), &performSelectionInitialMenu(3));
...
Ответ №3
menuLoop (3, & menu.displayInitialMenu(), & performSelectionInitialMenu (3));
Это не то, чего вы пытаетесь достичь. Во-первых, вы не можете принять адрес вещей, которые не являются переменными. Итак, вам нужно будет сделать следующее:
- удалите “&”.
- удалите “()” после displayInitialMenu и выполнитеSelectionInitialMenu, так как это означает, что эти функции будут вызываться, а возвращаемое значение, которое является недействительным в текущем случае, будет передано в menuLoop. Таким образом, вы не получите то, что вы пытаетесь достичь.
вам нужно сделать что-то вроде:
menuLoop (3, menu.displayInitialMenu, выполнитьSelectionInitialMenu, 3); Обратите внимание, что вам придется передать три в качестве дополнительного параметра.
а также соответственно изменить подпись menuLoop.
I am using DirectX 11 and trying to load variables locally in scope using XMLoadFloat4. I am doing a lot of it and names are pretty long so I don’t want to create bunch of local variables, however with code like this:
XMStoreFloat4(&vertices[0].normal, XMVector3Cross(
XMLoadFloat4(&(vertices[2].position - vertices[0].position)),
XMLoadFloat4(&(vertices[0].position - vertices[1].position))
));
I’m getting C2102. Do you know elegant way to create reference in place like this?
asked Dec 25, 2020 at 0:15
8
You can work around this issue for now by disabling /permissive- by changing «Conformance Mode» to «No» in the C/C++ -> Language project settings.
answered Jan 3, 2021 at 8:29
Do you know elegant way to create reference in place like this?
The function expects pointers and you’re trying to pass the address of temporaries which isn’t allowed. Just store the temporary results in variables and pass the addresses to those:
auto a = vertices[2].position - vertices[0].position;
auto b = vertices[0].position - vertices[1].position;
XMStoreFloat4(
&vertices[0].normal,
XMVector3Cross(
XMLoadFloat4(&a),
XMLoadFloat4(&b)
)
);
answered Dec 25, 2020 at 0:34
Ted LyngmoTed Lyngmo
78.6k5 gold badges51 silver badges95 bronze badges
2
I am using DirectX 11 and trying to load variables locally in scope using XMLoadFloat4. I am doing a lot of it and names are pretty long so I don’t want to create bunch of local variables, however with code like this:
XMStoreFloat4(&vertices[0].normal, XMVector3Cross(
XMLoadFloat4(&(vertices[2].position - vertices[0].position)),
XMLoadFloat4(&(vertices[0].position - vertices[1].position))
));
I’m getting C2102. Do you know elegant way to create reference in place like this?
asked Dec 25, 2020 at 0:15
8
You can work around this issue for now by disabling /permissive- by changing «Conformance Mode» to «No» in the C/C++ -> Language project settings.
answered Jan 3, 2021 at 8:29
Do you know elegant way to create reference in place like this?
The function expects pointers and you’re trying to pass the address of temporaries which isn’t allowed. Just store the temporary results in variables and pass the addresses to those:
auto a = vertices[2].position - vertices[0].position;
auto b = vertices[0].position - vertices[1].position;
XMStoreFloat4(
&vertices[0].normal,
XMVector3Cross(
XMLoadFloat4(&a),
XMLoadFloat4(&b)
)
);
answered Dec 25, 2020 at 0:34
Ted LyngmoTed Lyngmo
78.6k5 gold badges51 silver badges95 bronze badges
2
|
|
|
Ошибка при работе с указателями
, для «++» требуется левостороннее значение
- Подписаться на тему
- Сообщить другу
- Скачать/распечатать тему
|
|
Member Рейтинг (т): 16 |
Изучаю книгу Кернингана и Ритчи «Язык программирования С», при выполнении упражнения возник вопрос. Не могу понять почему при компиляции возникает ошибка в коде: main() { int argc2 = 4; char *argv2[] = {«hello.exe», «1», «2», «+»}; ++argv2; //error C2105: для «++» требуется левостороннее значение } В нижепреведённом коде ошибки не возникает: main(int argc, char *argv[]) { ++argv; } Никак немогу понять в чём разница и почему один код работает, а другой — нет. Компилирую в Microsoft Visual Studio 2008. В свойствах проекта указано «Компилировать как код С» |
Большой |
|
klepa83 char *argv2[] = {«hello.exe», «1», «2», «+»}; В этом случае argv2 это имя массива. Которое не может использоваться в арифметике указателей. Но имя массива в свою очередь может безболезненно сводиться к указателю на указатель. char** a = argv2; ++a; И вполне себе работать. main(int argc, char *argv[]) { ++argv; } argv это аргумент функции переданный по значению (т.е мы имеем копию указателя), что фактически означает что это указатель на указатель. и с ним работать вполне можно. Конечно можно и так писать main(int argc, char **argv) { ++argv; } Но первый вариант предпочтителен т.к. мы видим что в качестве аргумента функции передается массив указателей Сообщение отредактировано: Большой — 04.10.10, 09:00 |
klepa83 |
|
Member Рейтинг (т): 16 |
Большой |
0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
0 пользователей:
- Предыдущая тема
- C/C++: Общие вопросы
- Следующая тема
[ Script execution time: 0,0505 ] [ 16 queries used ] [ Generated: 30.01.23, 01:14 GMT ]
Fregat228 0 / 0 / 0 Регистрация: 24.11.2016 Сообщений: 11 |
||||
1 |
||||
11.12.2017, 23:47. Показов 2359. Ответов 1 Метки нет (Все метки)
0 |
|
|
|
Ошибка при работе с указателями
, для «++» требуется левостороннее значение
- Подписаться на тему
- Сообщить другу
- Скачать/распечатать тему
|
|
Member Рейтинг (т): 16 |
Изучаю книгу Кернингана и Ритчи «Язык программирования С», при выполнении упражнения возник вопрос. Не могу понять почему при компиляции возникает ошибка в коде: main() { int argc2 = 4; char *argv2[] = {«hello.exe», «1», «2», «+»}; ++argv2; //error C2105: для «++» требуется левостороннее значение } В нижепреведённом коде ошибки не возникает: main(int argc, char *argv[]) { ++argv; } Никак немогу понять в чём разница и почему один код работает, а другой — нет. Компилирую в Microsoft Visual Studio 2008. В свойствах проекта указано «Компилировать как код С» |
Большой |
|
klepa83 char *argv2[] = {«hello.exe», «1», «2», «+»}; В этом случае argv2 это имя массива. Которое не может использоваться в арифметике указателей. Но имя массива в свою очередь может безболезненно сводиться к указателю на указатель. char** a = argv2; ++a; И вполне себе работать. main(int argc, char *argv[]) { ++argv; } argv это аргумент функции переданный по значению (т.е мы имеем копию указателя), что фактически означает что это указатель на указатель. и с ним работать вполне можно. Конечно можно и так писать main(int argc, char **argv) { ++argv; } Но первый вариант предпочтителен т.к. мы видим что в качестве аргумента функции передается массив указателей Сообщение отредактировано: Большой — |
klepa83 |
|
Member Рейтинг (т): 16 |
Большой |
0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
0 пользователей:
- Предыдущая тема
- C/C++: Общие вопросы
- Следующая тема
[ Script execution time: 0,0579 ] [ 16 queries used ] [ Generated: 22.09.23, 11:11 GMT ]
мне было интересно, почему следующий код (уже закомментированы) вызоветC2102: '&' requires l-value
есть ли лучший способ, чтобы избежать использования tmp
переменной?
class a {
private:
int *dummy;
public:
int* get_dummy() const {
return dummy;
}
};
int main()
{
a aa;
// error C2102: '&' requires l-value
//int** me = &(aa.get_dummy());
// OK!
int *tmp = aa.get_dummy();
int** me = &(tmp);
}
5 ответов
, потому что a::get_dummy()
возвращает безымянный временный объект (указатель int).
Объект, возвращаемый функцией сидеть на вершине кадра стека и бессмысленно получать его адрес, так как это может быть недопустимо после окончания выражения.
вместо этого вы можете определить:
int **get_dummy() ... return &dummy;
вы можете думать о R-значении как о выражении, по существу, тогда как l-значение является фактическим объектом. У выражений нет адресов, и даже если бы они были, трудно представить, какой хороший адрес был бы. Легко понять, как адрес объекта может быть полезным.
немного сложно понять такую проблему абстрактно. Самый лучший способ развить понимание указателей и скомпилированных языков это изучение языка ассемблера.
нет.
какой адрес будет me
содержать иное? Вот вы дали ему адрес tmp
— но если вы замените его с int** me = &aa.get_dummy();
, куда она указывала?
на этот вопрос нет значимого ответа, поэтому стандарт требует, чтобы аргумент &
будьте lvalue.
на &
оператор должен быть применен к lvalue. Когда вызов aa.get_dummy()
не присваивается переменной, ее возвращаемое значение помещается только в стек, поэтому было бы глупо (и ошибочно) получить адрес элемента стека.
компилятор прав, согласно ISO C++ 5.3.1.3§:
результатом унарного оператора & является указатель на его операнд. Этот
операнд должен быть lvalue или квалифицированным id.
другими словами, вы можете взять адрес всего, что имя.
значения, возвращаемые из функции по стоимости не имеют имени и часто возвращаются через зарегистрироваться. Так что нет никакого»адрес » говорить о том, как значение не находится в памяти!
можно утверждать, что компилятор может быть умнее, обнаружить это и сохранить значение в стеке на время выражения, в котором используется адрес. Но это подвержено ошибкам (вы можете «утечь» указатель за пределы выражения) и, очевидно, будет расширение стандарта (т. е. не гарантируется совместимость). Так индекса MSVC просто запрещает.
увлекательно, компилятор is что умный когда дело доходит до ссылка к rvalue. Но нет такой функции указатель к rvalue.
чтобы ответить на ваш вопрос: попробуйте свести к минимуму взятие адресов вещей; взятие адреса переменной предотвращает оптимизатор от ввода его в регистр.
Но если вам нужно, верните ссылку вместо этого:
class a {
private:
int dummy;
public:
int get_dummy() const {
return dummy;
}
int& get_dummy() {
return dummy;
}
};
int main()
{
a aa;
int* me = &(aa.get_dummy());
}
обратите внимание, что имея const get_dummy()
строго не требуется, но поможет оптимизатору в контекстах rvalue.