У меня есть структура, определенная с помощью конструктора как такового:
struct Point {
double x; double y;
Point (double xx=0, double yy=0): x(xx),y(yy){};
};
Я могу создать такие точки, и эта работа прекрасна,
Point P0(0,0), P1(1,1);
Но я хочу иметь возможность изменить его как таковой:
P0 = (4,5); //no compilation error but garbage returned when printing P0
Не работает!
Кроме того, у меня есть такая функция, как я использую это
void Foo(Point P0, Point P1){
...do stuff
}
и я хочу передать следующий аргумент следующим образом:
Foo((1,2),(2,3)); //no compilation error but garbage returned
Я пробовал смотреть все это не очень ясно для меня.. любая помощь
(4,5)
эквивалентно только 5
, так как то, как работает оператор запятой: он оценивает первое выражение, отбрасывает результат, затем оценивает второй. Вы должны получить предупреждение компиляции об отброшенном выражении без побочных эффектов, если вы включите предупреждения.
В С++ 11 вы можете использовать инициализатор списка, чтобы делать то, что вы хотите:
P0 = {4,5};
Foo({1,2},{2,3});
Если вы застряли со старым диалектом, вам нужно будет прописать его:
P0 = Point(4,5);
Foo(Point(1,2), Point(2,3));
P0 = (4,5);
Это не делает то, что вы думаете.
Выражение (4,5)
оценивается как 5
. Это потому, что в нем содержится то, что называется оператором запятой. Оператор запятой сначала оценивает свой левый операнд, отбрасывает результат и затем оценивает свой второй операнд. Таким образом, это утверждение действительно эквивалентно
P0 = 5;
Теперь это в свою очередь эквивалентно
P0 = Point(5);
что эквивалентно
P0 = Point(5, 0);
так как у вас есть аргумент по умолчанию. Это не фигня. Он отлично определен.
Точно то же самое произойдет в вашем другом заявлении:
Foo((1,2),(2,3)); // same as Foo(Point(2, 0), Point(3, 0));
Чтобы исправить это, вы можете явно построить точки:
P0 = Point(4, 5);
Foo(Point(1, 2), Point(2, 3));
или, если у вас есть поддержка С++ 11, вы можете сделать это:
P0 = {4, 5};
Foo({1, 2}, {2, 3});
(Когда запятая происходит внутри фигурных скобок, она не является оператором запятой. Она разделяет элементы списка инициализаторов.)
В этом утверждении
P0 = (4,5); //no compilation error but garbage returned when printing P0
выражение (4,5)
является выражением с оператором comme. Его значением является второе подвыражение, равное 5.
Затем компилятор пытается преобразовать значение 5 в объект типа Point, чтобы присвоить его P0. Поскольку у вас есть конструктор преобразования
Point (double xx=0, double yy=0): x(xx),y(yy){};
то компилятор вызывает его с аргументами 5 и 0, которые являются Point( 5, 0 )
. Этот временный объект присваивается P0.
Вместо оператора запятой вам следует использовать список упрощенных init. Например
P0 = { 4, 5 };
при условии, что ваш компилятор поддерживает эту функцию C++ 11. В противном случае вам нужно явно указать конструктор в правой части выражения
P0 = Point( 4, 5 );
Вместо этого вы должны использовать P0 = Point (4, 5). Вызов Point (4, 5) создает временный объект, который затем копируется в P0 (на самом деле он обычно оптимизируется, поэтому фактическое копирование не требуется).