Ошибка c2102 для требуется левостороннее значение

Немного дополненный код из книги. Не знаю, почему выдаёт ошибку и, что самое удивительное, выдаёт ошибку не в мной написанном коде!

#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

Mikołaj Gogola's user avatar

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

Jack1488's user avatar

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 Lyngmo's user avatar

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

Mikołaj Gogola's user avatar

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

Jack1488's user avatar

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 Lyngmo's user avatar

Ted LyngmoTed Lyngmo

78.6k5 gold badges51 silver badges95 bronze badges

2

    msm.ru

    Нравится ресурс?

    Помоги проекту!

    >
    Ошибка при работе с указателями
    , для «++» требуется левостороннее значение

    • Подписаться на тему
    • Сообщить другу
    • Скачать/распечатать тему



    Сообщ.
    #1

    ,
    04.10.10, 08:00

      Member

      **

      Рейтинг (т): 16

      Изучаю книгу Кернингана и Ритчи «Язык программирования С», при выполнении упражнения возник вопрос. Не могу понять почему при компиляции возникает ошибка в коде:

      ExpandedWrap disabled

        main()

        {

            int argc2 = 4;

            char *argv2[] = {«hello.exe», «1», «2», «+»};

            ++argv2; //error C2105: для «++» требуется левостороннее значение

        }

      В нижепреведённом коде ошибки не возникает:

      ExpandedWrap disabled

        main(int argc, char *argv[])

        {

            ++argv;

        }

      Никак немогу понять в чём разница и почему один код работает, а другой — нет.

      Компилирую в Microsoft Visual Studio 2008. В свойствах проекта указано «Компилировать как код С»


      Большой



      Сообщ.
      #2

      ,
      04.10.10, 08:56

        klepa83
        Все достаточно просто!

        char *argv2[] = {«hello.exe», «1», «2», «+»};

        В этом случае argv2 это имя массива. Которое не может использоваться в арифметике указателей. Но имя массива в свою очередь может безболезненно сводиться к указателю на указатель.

        ExpandedWrap disabled

          char** a = argv2;

          ++a;

        И вполне себе работать.
        Во втором случае

        ExpandedWrap disabled

          main(int argc, char *argv[])

          {

              ++argv;

          }

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

        Конечно можно и так писать

        ExpandedWrap disabled

          main(int argc, char **argv)

          {

              ++argv;

          }

        Но первый вариант предпочтителен т.к. мы видим что в качестве аргумента функции передается массив указателей

        Сообщение отредактировано: Большой — 04.10.10, 09:00


        klepa83



        Сообщ.
        #3

        ,
        04.10.10, 09:03

          Member

          **

          Рейтинг (т): 16

          Большой
          Действительно всё оказалось достаточно просто и понятно :) Я както и забыл, что массив — это не совсем тоже что и указатель, таким образом проблема действительно решается. Спасибо!

          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

          0 пользователей:

          • Предыдущая тема
          • C/C++: Общие вопросы
          • Следующая тема

          Рейтинг@Mail.ru

          [ 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

          Метки нет (Все метки)


          Студворк — интернет-сервис помощи студентам

          C++
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          
          #include "stdafx.h"
          #include <iostream>
          #include <math.h>
          #include <conio.h>
          using namespace std;
           
           
          int _tmain(int argc, _TCHAR* argv[])
          {
              setlocale(LC_ALL,"Russian");
              float xp,xk,dX,F,a,x,b,c,xc;
              cout<<"Введiть Xпоч, Xкін, dX, a, b, c:";
              cin>>xp>>xk>>dX>>a>>b>>c;
              for (x=xp;xc=xk;x+=dX)
                  {
                  if ((x<0.6)&&(b+c!=0))
                  F=a*(x*x)+(b*b)+c;
                      else
                      if ((x>0.6)&&(b+c==0))
                      F=(x-a)/(x-c);
                          else
                          F=(x/c)+(x/a);
                  
                  if ((int)a^(int)b)&~((int)c|0) ---------------в этом рядке проблема
                  F=(int)F;
                  cout<<x<<"\t"<<F<<endl;
                  }
              getch();
              return 0;
          }



          0



            msm.ru

            Нравится ресурс?

            Помоги проекту!

            >
            Ошибка при работе с указателями
            , для «++» требуется левостороннее значение

            • Подписаться на тему
            • Сообщить другу
            • Скачать/распечатать тему



            Сообщ.
            #1

            ,

              Member

              **

              Рейтинг (т): 16

              Изучаю книгу Кернингана и Ритчи «Язык программирования С», при выполнении упражнения возник вопрос. Не могу понять почему при компиляции возникает ошибка в коде:

              ExpandedWrap disabled

                main()

                {

                    int argc2 = 4;

                    char *argv2[] = {«hello.exe», «1», «2», «+»};

                    ++argv2; //error C2105: для «++» требуется левостороннее значение

                }

              В нижепреведённом коде ошибки не возникает:

              ExpandedWrap disabled

                main(int argc, char *argv[])

                {

                    ++argv;

                }

              Никак немогу понять в чём разница и почему один код работает, а другой — нет.

              Компилирую в Microsoft Visual Studio 2008. В свойствах проекта указано «Компилировать как код С»


              Большой



              Сообщ.
              #2

              ,

                klepa83
                Все достаточно просто!

                char *argv2[] = {«hello.exe», «1», «2», «+»};

                В этом случае argv2 это имя массива. Которое не может использоваться в арифметике указателей. Но имя массива в свою очередь может безболезненно сводиться к указателю на указатель.

                ExpandedWrap disabled

                  char** a = argv2;

                  ++a;

                И вполне себе работать.
                Во втором случае

                ExpandedWrap disabled

                  main(int argc, char *argv[])

                  {

                      ++argv;

                  }

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

                Конечно можно и так писать

                ExpandedWrap disabled

                  main(int argc, char **argv)

                  {

                      ++argv;

                  }

                Но первый вариант предпочтителен т.к. мы видим что в качестве аргумента функции передается массив указателей

                Сообщение отредактировано: Большой


                klepa83



                Сообщ.
                #3

                ,

                  Member

                  **

                  Рейтинг (т): 16

                  Большой
                  Действительно всё оказалось достаточно просто и понятно :) Я както и забыл, что массив — это не совсем тоже что и указатель, таким образом проблема действительно решается. Спасибо!

                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

                  0 пользователей:

                  • Предыдущая тема
                  • C/C++: Общие вопросы
                  • Следующая тема

                  Рейтинг@Mail.ru

                  [ 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.


                  Понравилась статья? Поделить с друзьями:
                • Ошибка c21 suzuki gsxr
                • Ошибка c2061 синтаксическая ошибка идентификатор string
                • Ошибка c2059 синтаксическая ошибка using namespace
                • Ошибка c2212 00 заводской режим как снять
                • Ошибка c2039 c