Чи всі оператори C ++ щось повертають?


83

Всі оператори C ++, з якими я працював, повертають щось, наприклад, +оператор повертає результат додавання.

Чи всі оператори C ++ щось повертають, чи є деякі оператори C ++, які нічого не повертають?


7
Це залежить від того, наскільки вузько ви визначаєте термін "оператор".
молбдніло

12
Стандарт не вимагає цього - наприклад, ви можете реалізувати +=повернення void, але це не рекомендується. Також оператори викликів функцій можуть повернутися, voidі це дійсно
Mircea Ispas

Хм Я здогадуюсь, що оператор роздільної здатності ::нічого не повертає, але мені доведеться проконсультуватися зі стандартом, щоб переконатися.
Yksisarvinen

2
Чи контекст питання для типів C ++ надається лише, чи включає також визначені користувачем типи?
Eljay

@Eljay Тільки типи, що надаються на C ++.
user8240761

Відповіді:


112

Ні, не всі оператори щось повертають.

Хоча вони, мабуть, не зовсім те, про що ви думаєте, зауважте, що „ключові слова” deleteта delete[]C ++ насправді є операторами ; і вони визначаються як такі, що мають voidтип повернення - це означає, що вони не оцінюють до нуля (що не є "чимось").

З cppreference :

void operator delete  ( void* ptr ) noexcept;
void operator delete[]( void* ptr ) noexcept;

13
Мені подобається ваша відповідь, це змусило мене думати про питання інакше. delete, delete[], throw, (void)x;Лиття, ліва сторона ,оператора, з правого боку ,оператора , що дає void, А ?:потрійна , який використовує throwдля одного з плечей, dfri в operator void()(який був би визначається користувачем),眠りネロク's void operator()()(певний який був би користувач).
Eljay

10
Також бентежить те, що deleteоператор знищує об’єкт, а потім викликає operator delete. Ergo, то deleteоператор і operator deleteокремі речі :( stackoverflow.com/a/8918942/845092
мукають Duck

7
Не впевнені, чому ви цитуєте функції видалення, говорячи про оператор видалення. Але як би там не було.
Дедулікатор

4
@MooingDuck Вираз delete знищує об'єкт, а потім викликає operator delete.
NathanOliver

Чи враховується видалення як оператор, я думав, що об’єкт - це щось, що діє на переданий об’єкт ?? Для видалення не потрібно передавати або створювати будь-який об’єкт, щоб він працював ..... Так само, як printf .....
Yunfei Chen

82

Оператори спеціальних типів можуть бути перевантажені, щоб робити найдивніші речі.

наприклад, оператор + повертає результат додавання.

Не обов'язково:

#include <iostream>
struct foo {
    int value = 0;
    void operator+(int x) {
        value += x;
    }
};

int main () {
    foo f;
    f + 3;
}

Тут operator+додається ліва сторона до valueелемента, і його тип повернення недійсний. Це вигаданий приклад, але, загалом, не повернення чогось із користувацького оператора не є незвичайним.

Єдиний оператор, який може бути перевантажений і який вимагає повернення чогось, про що мені відомо, це operator->. Він повинен повернути необроблений вказівник або об'єкт, який має operator->.


Як не дивно, насправді немає обмежень щодо перевантаженого оператора, що повертає значення. Отже, оператори можуть повернути все, що завгодно. en.cppreference.com/w/cpp/language/operators
bracco23

5
@ braccor23 operator->є трохи особливим і потребує повернення або покажчика, або об'єкта, який має operator->, не впевнений, що є інші винятки
greatest_prime_is_463035818

1
Так, це єдине обмеження. Навіть не bool для операторів порівняння. Це виглядає по-справжньому дивним.
bracco23

9
@ idclev463035818: Можливо, більш корисним прикладом можуть бути Шаблони виразів. Наприклад, ви можете створити бібліотеку матриць, де operator*(Matrix const& left, Matrix const& right)повертається не Matrixа, а замість цього MatrixMul, так що якщо вона буде подана в operator+(Matrix const& left, MatrixMul const& right)операцію, це може бути сплавлене множення-додавання, яке ефективніше, ніж спочатку множення, а потім додавання.
Matthieu M.

1
@DarrelHoffman Коли <<і >>перевантажуються для операцій вводу-виводу, вони очікують повернення потоку, щоб ви могли їх каскадувати:stream << foo << bar;
Barmar

34

Натомість оператори нічого не повертають. Це просто лексичні елементи, які ми використовуємо для створення виразів мовою. Зараз вирази мають типи і можуть обчислюватися значеннями, і я припускаю, що це те, що ви маєте на увазі під операторами, які "повертають речі".

Ну, ну так. Існують вирази C ++ із типом void(і, отже, не обчислюють жодне значення). Одні очевидні, інші менш. Приємним прикладом буде

throw std::runtime_error()

throw- це вираз під граматикою C ++. Ви можете використовувати його в інших виразах, наприклад, в умовному виразі

return goodStatus() ? getValue() : throw std::runtime_error();

А тип виразу кидка - це void. Очевидно, оскільки це просто змушує виконання швидко йти в інше місце, вираз не має значення.


21

Жоден із вбудованих операторів C ++ щось не повертає . Перевантажені оператори C ++ повертають щось настільки, що позначення оператора є синтаксичним цукром для виклику функції.

Швидше, всі оператори оцінюють щось. Те, що щось має чітко визначене значення , а також тип . Навіть оператор виклику функції void operator()(/*params*/)є voidтипом.

Наприклад, +'a'це intтип зі значенням, 'a'кодованим на вашій платформі.

Якщо ваше запитання: "Чи можуть оператори C ++ мати voidтип повернення?" тоді відповідь, безумовно, так.


14
@ idclev463035818: Це термін повернення, з яким у мене проблема. Єдине, що в С ++ щось повертає, - це функція. Вирази оцінюють до чогось.
Вірсавія,

7
Оператори типів класів - це методи, які щось повертають
greatest_prime_is_463035818

4
Це важливий момент. Недбала термінологія призводить до плутанини. +1.
Піт Беккер,

3
@supercat - ваш коментар ганьбить купу працьовитих людей, включаючи мене. Ті з нас, хто писав стандарт, ніколи не очікували, що автори компіляторів заповнюватимуть деталі шляхом опитування інших компіляторів, теперішніх чи минулих. Метою стандарту було і є чітке визначення синтаксису та семантики мови програмування С ++. Так, результат не ідеальний; Є багато питань, розглянутих в останньому стандарті, які не розглядались у попередніх версіях. Це випливає з досвіду, визнаючи ускладнення, яких тоді просто не було.
Піт Беккер,

3
@ Peter-ReinstateMonica - ось сильніша версія. Вираз I++не повертає значення. Якщо тип i- це визначений користувачем тип, цей вираз реалізується як operator++, що є функцією, яка повертає значення. Ви називаєте це "синтаксичним цукром"; Я називаю це розмежуванням, яке має важливі наслідки.
Піт Беккер,

12

Ви можете фактично визначити оператор виклику функції, щоб нічого не повертати. Наприклад:

struct Task {
   void operator()() const;
};

17
Ви можете визначити майже будь-якого оператора, який нічого не поверне (і зіткнутися з гнівом розлюченої мафії, якій доведеться підтримувати цей код)
Yksisarvinen

7
@Yksisarvinen, але принаймні цей є потенційно корисним.
Mark Ransom

11

operator void (): визначена користувачем функція перетворення в void

Ви можете визначити своєрідно operator void()функцію перетворення, де компілятор буде навіть попередить вас про те , що Tдля voidфункції перетворення ніколи не буде використовуватися :

#include <iostream>

struct Foo {
    operator void() { std::cout << "Foo::operator void()!"; }
    // warning: conversion function converting 'Foo' to 
    //          'void' will never be used
};
    
int main() {
    Foo f;
    (void)f;            // nothing
    f.operator void();  // Foo::operator void()!
}

відповідно до [class.conv.fct] / 1

[...] Функція перетворення ніколи не використовується для перетворення (можливо cv-кваліфікованого) об’єкта в (можливо cv-кваліфікований) того самого типу об’єкта (або посилання на нього), у (можливо cv-кваліфікований) базовий клас такого типу (або посилання на нього), або до (можливо , CV-кваліфікованим) void. 117

( 117 ) Ці перетворення розглядаються як стандартні перетворення для цілей дозволу на перевантаження ([over.best.ics], [over.ics.ref]) і, отже, ініціалізація ([dcl.init]) та явне приведення. Перетворення в voidне викликає жодної функції перетворення ([expr.static.cast]). Незважаючи на те, що їх ніколи не викликають безпосередньо для здійснення перетворення, такі функції перетворення можуть бути оголошені і потенційно доступні через виклик функції віртуального перетворення в базовому класі.

Однак, як показано вище, ви все одно можете викликати його, використовуючи явний .operator void()синтаксис.


4

Оператори, визначені (вбудовані) мовою, є лексемами, що використовуються для виконання різних видів обчислень:

  • арифметика (+, -, *, /)
  • приріст / зменшення (++, -)
  • призначення (=, + =, - =, * =, / =,% =, >> =, << =, & =, ^ =, | =)
  • логіка (!, &&, ||)
  • реляційні (==,! =,>, <,> =, <=)
  • умовний?
  • кома

і так далі. Список може бути дуже великим.

У таких мовних посиланнях, як цей чи цей , на них не обов'язково посилаються як на щось, що повертає, просто виконуючи арифметичну або логічну операцію , порівняння, за допомогою якого змінна може бути змінена тощо.

Оскільки ця операція призводить до деякого значення, воно може інтерпретуватися як "повернене" оператором, але воно відрізняється від значення функції, що повертається.

З іншого боку, перевантажені оператори можуть бути визначені із значенням повернення якогось типу, навіть це може бути порожнім, тож, ні, не всі оператори повертають якесь значення в C ++.


3

Я припускаю, що ви говорите про функції оператора, а не про оператори як про синтаксичну одиницю мови.

Якщо ви перевантажуєте оператори будь-якого типу, ви можете фактично повернути все, що завгодно.

Це також має великий сенс, оскільки операції, такі як * або (), іноді можуть дуже інтуїтивно не повертати свій тип введення. Уявіть, як помножте складний тип числа на дійсний тип числа. Або оператор, який повертає елемент із колекції.

Ви також можете перевантажити оператори ++ та -, щоб нічого не повертати, таким чином усуваючи надзвичайно схильне до помилок змішування значення побічного ефекту та виразу, яке має стандартна версія.


2

Ні. Розглянемо ці два приклади тут:

int multiply (int a, int b) {
   return a*b;
}

void multiply_void(int a, int b) {
   cout << a*b;
//or cout << multiply(a,b);
}

Перша функція поверне ціле значення, яке може використовуватись іншою функцією. Значення повертається і зберігається в пам'яті для використання у разі потреби. Якщо ні, це не видно для людини і просто щасливо сидить у пам’яті.

Друга функція буде виводитись на пристрій виведення за замовчуванням (зазвичай консоль). Значення, повернене оператором множення, передається на вихідний пристрій. Функція multiply_void не повертає фактичне значення.


0

Всі оператори щось повертають. Їх називають операторами, тому що вони щось експлуатують, тому вони щось повернуть. Операторів, які не повертають щось, не можна називати операторами. Або вони повернуть якесь значення, або повернуть True або False залежно від ситуації.


0

Оператори самостійно не обов’язково щось повертають. Виклик функції повертає значення. Оператори можуть мати значення. Оператори іноді можуть викликати функції. Приклади включають:

• Оператор виклику функції.

• Перевантажений оператор, який трансформується у виклик функції.

• оператор new, який викликається як частина a виразу new , є викликом функції.

Моя єдина мета згадування викликів функцій - уточнити результат проти повернення. На основі вивчення всіх 126 випадків "повернення" та слів, що походять від нього, у [expr] , розділ, схоже, обережно використовує слово return для посилання на:

• результат виклику функції

• аспекти управління потоком, пов’язані з корутинами

Гаразд, цього достатньо педантизму щодо результату проти повернення.


0

Оператори C ++ повертають щось чи ні, це залежить від того, як ви ними користувались. Вбудовані оператори C ++ повертають деяке значення до тих пір, доки вони не будуть примусовими для повернення void.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.