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