Ошибка компилятора c2102

The compiler is right, according to ISO C++ § 5.3.1.3:

The result of the unary & operator is a pointer to its operand. The
operand shall be an lvalue or a qualified-id.

In other words, you can take an address of anything that has a name.

Values returned from functions by-value have no name and are often returned via a register. So there is no «address» to speak of as the value is not residing in memory!

One could argue that the compiler could be smarter, detect this and store the value on the stack for the duration of the expression in which the address is used. But that is error-prone (you can «leak» a pointer to outside the expression), and would clearly be an extension of the standard (i.e. not guaranteed to be compatible). So MSVC simply prohibits it.

Entertainingly, the compiler is that smart when it comes to a reference to an rvalue. But there is no such functionality for a pointer to an rvalue.

To answer your question: try to minimize taking addresses of stuff; taking an address of a variable prevents the optimizer from putting it into a register.
But if you have to, return a reference instead:

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());
}

Note that having a const get_dummy() is not strictly needed, but will help the optimizer in rvalue contexts.

Permalink

Cannot retrieve contributors at this time

description title ms.date f1_keywords helpviewer_keywords ms.assetid

Learn more about: Compiler Error C2102

Compiler Error C2102

11/04/2016

C2102

C2102

d15b5fa3-fa46-4cd4-a3d2-3661646ecb7a

Compiler Error C2102

‘&’ requires l-value

The address-of operator ( & ) must have an l-value as operand.

description title ms.date f1_keywords helpviewer_keywords ms.assetid

Learn more about: Compiler errors C2100 through C2199

Compiler errors C2100 through C2199

04/21/2019

C2119

C2123

C2125

C2126

C2127

C2136

C2176

C2187

C2189

C2119

C2123

C2125

C2126

C2127

C2131

C2136

C2176

C2187

C2189

1ccab076-0954-4386-b959-d3112a6793ae

Compiler errors C2100 through C2199

The articles in this section of the documentation explain a subset of the error messages that are generated by the compiler.

[!INCLUDEerror-boilerplate]

Error messages

Error Message
Compiler error C2100 illegal indirection
Compiler error C2101 ‘&’ on constant
Compiler error C2102 ‘&’ requires l-value
Compiler error C2103 ‘&’ on register variable
Compiler error C2104 ‘&’ on bit field ignored
Compiler error C2105 operator‘ needs l-value
Compiler error C2106 operator‘: left operand must be l-value
Compiler error C2107 illegal index, indirection not allowed
Compiler error C2108 subscript is not of integral type
Compiler error C2109 subscript requires array or pointer type
Compiler error C2110 ‘+’: cannot add two pointers
Compiler error C2111 ‘+’: pointer addition requires integral operand
Compiler error C2112 ‘-‘: pointer subtraction requires integral or pointer operand
Compiler error C2113 ‘-‘: pointer can only be subtracted from another pointer
Compiler error C2114 operator‘: pointer on left; needs integral value on right
Compiler error C2115 operator‘: incompatible types
Compiler error C2116 function parameter lists differed
Compiler error C2117 identifier‘: array bounds overflow
Compiler error C2118 negative subscript
Compiler error C2119 identifier‘: the type for ‘type‘ cannot be deduced from an empty initializer
Compiler error C2120 ‘void’ illegal with all types
Compiler error C2121 ‘#’: invalid character: possibly the result of a macro expansion
Compiler error C2122 identifier‘: prototype parameter in name list illegal
Compiler error C2123 identifier‘: alias templates cannot be explicitly or partially specialized
Compiler error C2124 divide or mod by zero
Compiler error C2125 ‘constexpr’ is incompatible with ‘token
Compiler error C2126 identifier‘ cannot be declared with ‘constexpr’ specifier
Compiler error C2127 identifier‘: illegal initialization of ‘constexpr’ entity with a non-constant expression
Compiler error C2128 function‘: alloc_text/same_seg applicable only to functions with C linkage
Compiler error C2129 static function ‘identifier‘ declared but not defined
Compiler error C2130 #line expected a string containing the filename, found ‘token
Compiler error C2131 expression did not evaluate to a constant
Compiler error C2132 syntax error: unexpected identifier
Compiler error C2133 identifier‘: unknown size
Compiler error C2134 function‘: call does not result in a constant expression
Compiler error C2135 operator‘: illegal bit field operation
Compiler error C2136 authoring API contract not allowed
Compiler error C2137 empty character constant
Compiler error C2138 illegal to define an enumeration without any members
Compiler error C2139 class‘: an undefined class is not allowed as an argument to compiler intrinsic type trait ‘trait
Compiler error C2140 type‘: a type that is dependent on a generic type parameter is not allowed as an argument to compiler intrinsic type trait ‘trait
Compiler error C2141 array size overflow
Compiler error C2142 function declarations differ, variable parameters specified only in one of them
Compiler error C2143 syntax error: missing ‘token1‘ before ‘token2
Compiler error C2144 syntax error: ‘type‘ should be preceded by ‘token2
Compiler error C2145 syntax error: missing ‘token‘ before identifier
Compiler error C2146 syntax error: missing ‘token‘ before identifier ‘identifier
Compiler error C2147 syntax error: ‘token‘ is a new keyword
Compiler error C2148 total size of array must not exceed 0xvalue bytes
Compiler error C2149 identifier‘: named bit field cannot have zero width
Compiler error C2150 identifier‘: bit field must have type ‘int’, ‘signed int’, or ‘unsigned int’
Compiler error C2151 more than one language attribute
Compiler error C2152 identifier‘: pointers to functions with different attributes
Compiler error C2153 integer literals must have at least one digit
Compiler error C2154 type‘: only enumeration type is allowed as an argument to compiler intrinsic type trait ‘trait
Compiler error C2155 ‘?’: invalid left operand, expected arithmetic or pointer type
Compiler error C2156 pragma must be outside function
Compiler error C2157 identifier‘: must be declared before use in pragma list
Compiler error C2158 type‘: #pragma make_public directive is currently supported for native non-template types only
Compiler error C2159 more than one storage class specified
Compiler error C2160 ‘##’ cannot occur at the beginning of a macro definition
Compiler error C2161 ‘##’ cannot occur at the end of a macro definition
Compiler error C2162 expected macro formal parameter
Compiler error C2163 function‘: not available as an intrinsic function
Compiler error C2164 function‘: intrinsic function not declared
Compiler error C2165 modifier‘: cannot modify pointers to data
Compiler error C2166 l-value specifies const object
Compiler error C2167 function‘: too many actual parameters for intrinsic function
Compiler error C2168 function‘: too few actual parameters for intrinsic function
Compiler error C2169 function‘: intrinsic function, cannot be defined
Compiler error C2170 identifier‘: not declared as a function, cannot be intrinsic
Compiler error C2171 operator‘: illegal on operands of type ‘type
Compiler error C2172 function‘: actual parameter is not a pointer: parameter number
Compiler error C2173 function‘: actual parameter is not a pointer: parameter number, parameter list number
Compiler error C2174 function‘: actual parameter has type ‘void’: parameter number, parameter list number
Compiler error C2175 locale‘: invalid locale
Compiler error C2176 a return statement cannot appear in the handler of a function-try-block associated with a constructor
Compiler error C2177 constant too big
Compiler error C2178 identifier‘ cannot be declared with ‘specifier‘ specifier
Compiler error C2179 type‘: an attribute argument cannot use type parameters
Compiler error C2180 controlling expression has type ‘type
Compiler error C2181 illegal else without matching if
Compiler error C2182 identifier‘: illegal use of type ‘void’
Compiler error C2183 syntax error: translation unit is empty
Compiler error C2184 type‘: illegal type for __except expression
Compiler error C2185 identifier‘: illegal based allocation
Compiler error C2186 operator‘: illegal operand of type ‘void’
Compiler error C2187 syntax error: ‘token‘ was unexpected here
Compiler error C2188 number‘: too big for wide character
Compiler error C2189 ‘alignas’ attribute cannot be applied to a bit-field, a function parameter, an exception declaration, or a variable declared with ‘register’ storage class
Compiler error C2190 first parameter list longer than second
Compiler error C2191 second parameter list longer than first
Compiler error C2192 parameter ‘number‘ declaration different
Compiler error C2193 identifier‘: already in a segment
Compiler error C2194 identifier‘: is a text segment
Compiler error C2195 identifier‘: is a data segment
Compiler error C2196 case value ‘value‘ already used
Compiler error C2197 function‘: too many arguments for call
Compiler error C2198 function‘: too few arguments for call
Compiler error C2199 syntax error: found ‘identifier (‘ at global scope (was a declaration intended?)

See also

C/C++ Compiler and build tools errors and warnings
Compiler errors C2000 — C3999, C7000 — C7999

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

#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 ]  

          Понравилась статья? Поделить с друзьями:
        • Ошибка компилятора c2088
        • Ошибка компилятора c2079
        • Ошибка компилятора c2065
        • Ошибка компилятора c2064
        • Ошибка компилятора c2061