Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
Alvin Seville
334 / 266 / 132
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 9
1

Что означает в C++ запись вида auto f() -> T?

28.12.2018, 10:00. Показов 1036. Ответов 14
Метки нет (Все метки)

C++
1
2
3
4
auto f(const int x) -> float
{
    return float(x) / 3;
}
Что означает в C++ запись вида auto f() -> T? ReSharper предложил мне такую замену, я хочу понять что это значит. Автовывод типа возвращаемого значения функции, но зачем тогда float после стрелочки?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.12.2018, 10:00
Ответы с готовыми решениями:

что означает запись вида x = y * f == c
Сабж в шапке. Исходная строка var isOddFace = j % 2 == 1; интересует именно двойное равенство в...

не понимаю запись вида http://что-то/index.php?что-то=&where=что-то
Допучтим видим в статус строке такую запись: http://что-то/index.php?что-то=&where=что-то меня...

Что означает запись в скобках и что возвращает return
Всем привет! Начал читать книгу BecomeAnXcoder и тут появился вопрос. В пример приведен такой код...

Что означает запись?
Добрый день! Подскажите, пожалуйста, что означает запись: \int_{0}^{\infty}xdF(x) какова...

14
155 / 107 / 36
Регистрация: 27.06.2018
Сообщений: 248
28.12.2018, 10:36 2
auto говорит компилятору, чтобы он сам искал подходящий тип для переменной.
Но в случае использования auto для функции, тип должен быть определён программистом, поэтому явно указывается возвращаемый тип
0
Alvin Seville
334 / 266 / 132
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 9
28.12.2018, 10:50  [ТС] 3
Human_foot, а какой смысл тогда auto тут, если тип все равно указывать?
0
2054 / 1531 / 167
Регистрация: 14.12.2014
Сообщений: 13,326
28.12.2018, 11:07 4
Соколиный глаз, перед списком аргументов их тип еще неизвестен компилятору. А если тип возврата нужно из него выводить тогда это и используется. К примеру:
C++
1
2
template <class LT,class RT>
auto operator * (LT Left,RT Right) -> decltype(Left.x * Right.x) { // вычисление значения}
1
494 / 208 / 70
Регистрация: 27.05.2016
Сообщений: 554
28.12.2018, 11:31 5
Стоит отметить что в С++14 trailing return type не являеться об`язательным, а возвращаемый тип может быть определен из тела функции.
0
884 / 340 / 78
Регистрация: 17.05.2015
Сообщений: 1,096
28.12.2018, 11:48 6
Цитата Сообщение от Human_foot Посмотреть сообщение
Но в случае использования auto для функции, тип должен быть определён программистом
А теперь правильный ответ: не должен.
Программист может явно указать тип возвращаемого значения.
А может и не указывать.

На самом деле запись вида:

C++
1
auto functionName(param) -> T
Это - альтернативная запись вида:
C++
1
T functionName(param)
Всего лишь синтаксический сахар.
И ничего более.
0
155 / 107 / 36
Регистрация: 27.06.2018
Сообщений: 248
28.12.2018, 12:04 7
Цитата Сообщение от eva2326 Посмотреть сообщение
не должен.
А теперь правильный ответ: зависит от версии стандарта
0
2054 / 1531 / 167
Регистрация: 14.12.2014
Сообщений: 13,326
28.12.2018, 12:05 8
Цитата Сообщение от notAll Посмотреть сообщение
а возвращаемый тип может быть определен из тела функции.
Может. Но не всегда это удобно. К примеру многоэтажный decltype для определения типа возврата, и ветвистый свитч на возврате.
0
884 / 340 / 78
Регистрация: 17.05.2015
Сообщений: 1,096
28.12.2018, 12:26 9
Цитата Сообщение от Human_foot Посмотреть сообщение
А теперь правильный ответ: зависит от версии стандарта
Нет, не зависит.

Нет ни одной версии стандарта, в которой бы программист
был обязан для функций использовать запись вида:
auto foo() -> T
0
Human_foot
28.12.2018, 12:30
  #10

Не по теме:

Пример кода можно?

0
884 / 340 / 78
Регистрация: 17.05.2015
Сообщений: 1,096
28.12.2018, 13:10 11
Цитата Сообщение от Соколиный глаз Посмотреть сообщение
Human_foot, а какой смысл тогда auto тут, если тип все равно указывать?
Высказывание этого товарище - очевидно не имеет смысла.

Явное указание T нужно лишь там, где оно необходимо.
А необходимо оно может быть только в трёх случаях:

1.
Когда наружу нужно вернуть тип данных,
не соответствующий результату работы

Пример:
C++
1
2
3
4
5
6
7
8
9
10
auto load(const char* filename) -> bool
{
    std::ostream os(filename);
    load_content(os);
    return os; // <--- из-за явного указания bool
 
    // наружу вернётся true, 
    // если os находится в валидном состоянии
 
}
Это - притянутый за уши пример, потому что в таких случаях проще сразу написать в классическом стиле:
C++
1
 bool load(const char* filename)
2.
auto вычисляет типы согласно своим правилам,
отличным от правил буквальной подстановки decltype.

auto подчиняется правилам "схлопывания" типов
по аналогии c forward reference

(подробности гугли: хабр универсальные ссылки)
(подробности гугли: хабр идеальная передача аргументов)

В результате, на выходе может получится не тот тип данных,
на который мы рассчитывали.

Поэтому, иногда мы вынужденны дополнительно явно указывать,
что именно мы хотим.

Пример:

На языке с++ литерная текстовая константа имеет тип "массив".
Допустим, хотим вернуть из функции ссылку на статический массив.

C++
1
2
3
4
auto get_name() noexcept 
{
    return "hello";
}
Однако, согласно правилам вывода типов для auto
результат будет const char*.

Не то, что мы ожидали...

Давайте скажем компилятору, что возвращая ссылку на массив,
мы хотим получать именно ссылку, а не указатель.
Эта мера не позволит компилятору выполнить неявное приведение типов:

C++
1
2
3
4
auto get_name() noexcept -> auto&
{
    return "hello";
}
Теперь возвращаемый тип соответствует фактическому.

другой способ добиться того же самого:
C++
1
2
3
4
decltype(auto) get_name() noexcept
{
    return "hello";
}

3.
Моё любимое.
Автовывод типов значений имеет под собой "шаблонную" природу.
Он подчиняется тем же правилам, которым подчиняются обычные классические шаблоны с++
А значит, можно задействовать различные трюки.

Например SFINAE:
Задача: написать универсальную функцию begin,
которая сможет работать не только с контейнерами,
или с массивами, но и с сишными строчками, и с итераторами:

C++
1
2
3
4
5
6
7
        template <class str>
        constexpr auto begin(str& s) noexcept -> decltype (::std::begin(s))
            { return ::std::begin(s); }
 
        template <class ptr>
        constexpr auto begin(ptr* p) noexcept -> decltype (&(*p))
            { return p; }
Для первой перегрузки, мы сообщили компилятору:
тип возвращаемого значения должен быть точно таким же,
какой вернёт вызов std::begin(s)
Если же окажется, что аргумент s не совместим с std::begin,
тогда весь шаблон зафейлится, и данная перегрузка вообще не будет использована.

В этом случае компилятор рассмотрит вторую перегрузку.
Для неё тип возвращаемого значения - это "разыменовать p, и взять адрес"
Такое можно провернуть только с указателями, или с итераторами.


В результате получаем:
для всех типов совместимых с std::begin отработает первый вариант.
для указательных типов сработает второй вариант.

Oби перегрузки не конфликтуют друг с другом,
потому что благодаря указанному типу возвращаемого значения,
срабатывает SFINAE, которое оставляет в живых только одну заведомо подходящую версию
1
2054 / 1531 / 167
Регистрация: 14.12.2014
Сообщений: 13,326
28.12.2018, 13:25 12
Цитата Сообщение от eva2326 Посмотреть сообщение
другой способ добиться того же самого:
а типа
C++
1
2
3
4
auto& get_name() noexcept 
{
    return "hello";
}
не тот же самый результат даст?
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
28.12.2018, 16:45 13
Цитата Сообщение от eva2326 Посмотреть сообщение
Задача: написать универсальную функцию begin,
которая сможет работать не только с контейнерами,
или с массивами, но и с сишными строчками, и с итераторами:
1) С чего вдруг вторая перегрузка будет выбрана для итератора?
2) Задача написать только функцию begin? А end как будет выглядеть?
0
Croessmah
28.12.2018, 18:27
  #14

Не по теме:

Эхххх, Дениска...

0
884 / 340 / 78
Регистрация: 17.05.2015
Сообщений: 1,096
29.12.2018, 12:36 15
Цитата Сообщение от rat0r Посмотреть сообщение
1) С чего вдруг вторая перегрузка будет выбрана для итератора?
вариант с boost
https://rextester.com/HZM35068
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
namespace tools 
{
   template <class str>
   constexpr auto begin(str& s) noexcept -> decltype (::std::begin(s))
       { 
       
std::cout << "[begin] ";
       return ::std::begin(s); 
   }
 
   template <class iter>
   constexpr auto begin(iter& i) noexcept -> decltype ( (&(*i), i)  )
       { 
       std::cout << "[iter] ";
       return i;
   }
 
   template <class ptr>
   constexpr auto begin(ptr* p) noexcept -> decltype (&(*p))
       { 
       std::cout << "[ptr] ";
       return p; 
   }
 
} //namespace tools 
 
int main()
{
   const char arr[]      = "hello";
   const char* ptr       = arr;
   const std::string str = arr;
   const auto itr        = str.cbegin();
  
   const fs::directory_iterator dir(fs::current_path());
   
   { auto it =  tools::begin(dir); std::cout << "dir: " << it->path() << '\n'; }    
   { auto it =  tools::begin(arr); std::cout << "arr: " << it         << '\n'; }
   { auto it =  tools::begin(ptr); std::cout << "ptr: " << it         << '\n'; }
   { auto it =  tools::begin(str); std::cout << "str: " << &(*it)     << '\n'; }
   { auto it =  tools::begin(itr); std::cout << "itr: " << &(*it)     << '\n'; }
}
тоже самое, только std
https://rextester.com/HZM35068



Цитата Сообщение от rat0r Посмотреть сообщение
А end как будет выглядеть?
На самом деле реальный код гораздо сложнее и технологичнее.

Учитывается множество нюансов.
Итератор как минимум должен уметь определять факт своей инвалидности:
C++
1
while(it) ++it;
Как это умеют делать итераторы в стиле java (filesystem, например)

Если вам так интересно, можно завести отдельную тему)))
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.12.2018, 12:36

Что означает запись [A, A*] = 0?
Что означает запись = 0?

Что означает запись .5?
Что означает .5 на C? Спасибо :) Потрудитесь хотя бы одну строку набрать текстом, а не...

Что означает запись?
(int len, int i, int j) min = (j + 1, 0, j); min - массив

Что означает запись
Привет. Верна ли, и если да, то что значит данная запись и для чего она используется: bool...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.