Чи повинен кінцевий стиль синтаксису типу повернення стати типовим для нових програм C ++ 11? [зачинено]


92

C ++ 11 підтримує новий синтаксис функції:

auto func_name(int x, int y) -> int;

На даний момент ця функція буде оголошена як:

int func_name(int x, int y);

Здається, новий стиль ще не широко прийнятий (скажімо в gcc stl)

Однак, чи слід віддавати перевагу цьому новому стилю скрізь у нових програмах C ++ 11, чи він буде використовуватися лише за потреби?

Особисто я віддаю перевагу старому стилю, коли це можливо, але кодова база зі змішаними стилями виглядає досить потворно.


29
Це в основному для decltypeаргументів.
Cat Plus Plus

те, що говорить CatPlusPlus: немає сенсу використовувати це у вашому прикладі
stijn

@Cat Plus Plus Це означає, що ви залишаєте речі такими, як вони є в C ++ 03, якщо вам не потрібно отримати тип повернення?
mirk

1
Некрасиво, що перед кожною функцією потрібно вказувати "авто". Це схоже на шалену відповідь C ++ на "def" python?
Ерік Аронесті,

Відповіді:


110

Є певні випадки, коли ви повинні використовувати кінцевий тип повернення. Найголовніше, тип лямбда-повернення, якщо він вказаний, повинен бути вказаний через кінцевий тип повернення. Крім того, якщо ваш тип повернення використовує a, decltypeякий вимагає, щоб імена аргументів були в області дії, слід використовувати кінцевий тип повернення (однак, як правило, його можна використовувати declval<T>для обходу останньої проблеми).

Тип кінцевого повернення має деякі інші незначні переваги. Наприклад, розглянемо визначення вбудованої функції-члена, використовуючи традиційний синтаксис функції:

struct my_awesome_type
{
    typedef std::vector<int> integer_sequence;

    integer_sequence get_integers() const;
}; 

my_awesome_type::integer_sequence my_awesome_type::get_integers() const
{
    // ...
}

Тип typedefs члена не застосовується доти, доки назва класу не з’явиться раніше ::get_integers, тому нам доведеться повторити кваліфікацію класу двічі. Якщо ми використовуємо кінцевий тип повернення, нам не потрібно повторювати ім'я типу:

auto my_awesome_type::get_integers() const -> integer_sequence
{
    // ...
}

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

У своїй сесії "Fresh Paint" на C ++ Now 2012 Алісдейр Мередіт зазначив, що якщо ви послідовно використовуєте кінцеві типи повернення, імена всіх ваших функцій акуратно вирівнюються:

auto foo() -> int;
auto bar() -> really_long_typedef_name;

Я використовував кінцевий повертаються типи всюди в CxxReflect , так що якщо ви шукаєте приклад того , як код виглядає використовувати їх послідовно, ви подивіться там (наприклад, можете клас ).type


1
Схоже, що консенсусу ще немає, але цікаво подивитися на CxxReflect з новим стилем.
mirk

Привіт, Джеймсе. Цю відповідь, можливо, можна зробити більш точною у світлі стандарту C ++ 14.
Дрю Дорман

@DrewDormann Що б ви додали / змінили?
underscore_d

Вирівнювання насправді є великим плюсом, до того моменту, коли я хотів, щоб тут було нове ключове слово "func", яке б замінило безглузде "auto".
Йохан Буле,

67

На додаток до того, що сказали інші, кінцевий тип повернення також дозволяє використовувати this, що інакше не дозволяється

struct A {
  std::vector<int> a;

  // OK, works as expected
  auto begin() const -> decltype(a.begin()) { return a.begin(); }

  // FAIL, does not work: "decltype(a.end())" will be "iterator", but 
  // the return statement returns "const_iterator"
  decltype(a.end()) end() const { return a.end(); }
};

У другій декларації ми використовували традиційний стиль. Однак, оскільки thisце не дозволено в цій позиції, компілятор не використовує його неявно. Отже, a.end()використовує статично оголошений тип, aщоб визначити, яке endперевантаження vector<int>його буде викликати, що в кінцевому підсумку є неконстантною версією.


2
Хоча це хороша / акуратна демонстрація концепції (використання членів у типах повернення), це смішно, оскільки в C ++ 14 вказівка ​​типу є абсолютно зайвою у вбудованому визначенні без перетворення; тепер ми можемо просто використовувати відрахування типу повної віддачі. : P
underscore_d

27

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

void (*get_func_on(int i))(int);

з

auto get_func_on(int i) -> void (*)(int);

Однак можна стверджувати, що кращої читабельності можна досягти, просто ввівши псевдонім типу для покажчика функції:

using FuncPtr = void (*)(int);
FuncPtr get_func_on(int i);

10

Дивіться цю приємну статтю: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html Дуже хороший приклад, коли використовувати цей синтаксис без decltype в грі :

class Person
{
public:
    enum PersonType { ADULT, CHILD, SENIOR };
    void setPersonType (PersonType person_type);
    PersonType getPersonType ();
private:
    PersonType _person_type;
};

auto Person::getPersonType () -> PersonType
{
    return _person_type;
}

І блискуче пояснення, також викрадене у статті Алекса Аллаїна "Оскільки повертане значення йде в кінці функції, а не перед нею, не потрібно додавати область класу".

Порівняйте з цим можливим випадком, коли один випадково забуває про область класу, а для більшої катастрофи інший PersonType визначається в глобальній області:

typedef float PersonType; // just for even more trouble
/*missing: Person::*/
PersonType Person::getPersonType ()
{
    return _person_type;
}

7
Я не впевнений, що це потрапляє в категорію "катастрофа": якщо тип помилковий, код не компілюється. Помилки виконання можуть мати згубні наслідки; помилок під час компіляції, не так вже й багато.
James McNellis

4
@JamesMcNellis порівняє вихідні дані компілятора: prog.cpp:13:12: error: prototype for 'PersonType Person::getPersonType()' does not match any in class 'Person'проти prog.cpp:13:1: error: 'PersonType' does not name a type першої помилки компілятора, принаймні для мене, гірше зрозуміти.
PiotrNycz

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