LINUX.ORG.RU

Ответ на: комментарий от fsb4000

Интересно, а какие-нибудь требования к к алгоритму вывода auto стандартом предусмотрены? Или компилируемость любой функции, возвращающей auto, зависит от версии компилятора?

monk ★★★★★
()
Ответ на: комментарий от fsb4000

Нормальное поведение. Нельзя определить тип из пустого листа инициализации. Я хотела другое, когда тип можно вывести, но компилятор не может, например из-за ограничения самого механизма вывода.

Lzzz
() автор топика
Ответ на: комментарий от fsb4000

Хорошо, спрошу так. Для вывода типа выражения имеется достаточно информации. Всегда компилятор может вывести тип, или механизм вывода имеет ограничения? Например плохо работает вывод параметров шаблона класса для очень сложных классов с переменным числом аргументов в шаблоне.

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

Всегда, насколько знаю. decltype(auto) точный тип, auto - тип на который сделали decay(отбрасывает &, &&, const, volatile)

Вот можешь ещё тут посмотреть, тут проще читать чем стандарт: https://en.cppreference.com/w/cpp/language/auto

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

decltype(auto) точный тип

Щито??? Ты вообще читал, как из типа выражения expr определяется тип, который будет представлять decltype(expr)?

anonymous
()
Ответ на: комментарий от anonymous

Читал, и что не так? Полные правила написаны как в стандарте, так и в cppreference.

Я написал в двух словах характеристики, которых достаточно для многих случаев:

decltype(auto) сохраняет модификаторы

auto нет:

https://gcc.godbolt.org/z/776vfK

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Читал, и что не так?

Ок, точный тип чего даёт decltype(auto)?

anonymous
()
Ответ на: комментарий от Lzzz

Компилятор всегда способен вывести тип. Иначе это баг. Выведение типа это не новомодная фишка придуманная в угоду смузихипстерам. Это логичное расширение возможностей, предоставляемых компилятором. Все необходимое для вывода типа в компиляторе было уже давным давно, нужно было лишь оформить это в самом языке.

yetanother ★★
()
Последнее исправление: yetanother (всего исправлений: 1)
Ответ на: комментарий от yetanother

Скажи это какому-нибудь GHC и хаскелю, там тупняк компилятора обычное дело, когда он не справляется с дюжей полиморфностью вида a -> a -> a

anonymous
()

Вывод типов на 100% не работает ни в одном из популярных языков, включая Haskell - тупая машина не может заменить человека. Увы, специально не записывал такие случаи)

dave ★★★★★
()
Ответ на: комментарий от dave

ни в одном из популярных языков

…А непопулярный Nemerle ЕМНИП итеративно решал неполную систему уравнений. Выводя даже типы параметров по использованию (только это уже дичь ИМХО).

dimgel ★★★★★
()
Ответ на: комментарий от yetanother
std::vector<int> foo() {
  return std::vector<int>{};
}

выводит

std::vector<int> foo() {
  return std::vector{};
}

не выводит, хотя контекстной информации достаточно.

cdshines ★★★★★
()
Последнее исправление: cdshines (всего исправлений: 1)
Ответ на: комментарий от thunar

А у вас CTAD только недавно появился, да? Я поковырял только что, std::vector v{1,2}; можно только с c++17 делать, до него нужно руками писать std::vector<int>.

Ну, в принципе, я хотел сказать, что иногда вывод типа возможен только по call-site (типа как здесь https://doc.rust-lang.org/stable/rust-by-example/types/inference.html), и если бы я захотел так сделать в c++, то (пока?) так не получится:

std::vector v{}; // nope
v.push_back(2);
cdshines ★★★★★
()
Последнее исправление: cdshines (всего исправлений: 1)
Ответ на: комментарий от cdshines

А Rust недавно появился да? Там ещё не придумали что можно выводить тип возвращаемого значения у функций?

Я тут поковырял rust nightly, и пока возвращаемое значение у функции нужно писать руками :(

pub fn square(num: i32) /*-> i32*/ { // nope
    num * num
}

Дарю идею.

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Надеюсь и не запилят этот ужас. А для бытовых задач есть -> impl T.

RazrFalcon ★★★★★
()
Ответ на: комментарий от yetanother

Правильно, статический язык не вывести типы не может. Правда таких языков почти нет, а всё остальное - бездарная скриптуха с фейковым выводом. От того такие вопросы и появляются.

anonymous
()
Ответ на: комментарий от cdshines

А у вас CTAD только недавно появился, да? Я поковырял только что, std::vector v{1,2}; можно только с c++17 делать, до него нужно руками писать std::vector.

Зачем ты закукарекал о C++17? Одно никак не связано с другим.

так не получится:

Ты обгадился со всем остальным и решил ретранслировать методичку? Не сработает. В говнорасте там нет никакого вывода типов. Тебя обманули.

anonymous
()
Ответ на: комментарий от cdshines

А чего ты так быстро слился? Ой, оказалось, что вывода типов в недоязычке нет? Как же так? Они не обгадились - это их решение. Сильно.

anonymous
()
Ответ на: комментарий от fsb4000

А Rust недавно появился да? Там ещё не придумали что можно выводить тип возвращаемого значения у функций?

Там просто принципиально отказались от этого. В OCaml откуда и содран вывод типов раста возвращаемое значение без проблем выводится.

anonymous
()
Ответ на: комментарий от dimgel

А непопулярный Nemerle ЕМНИП итеративно решал неполную систему уравнений.

Ну это для функциональщины считай норма алгоритм Хиндли — Милнера тоже приводится к системе уравнений.
В том же расте вообще пролог встроили чтобы разрешать свойства трайтов https://rust-lang.github.io/chalk/book/

anonymous
()
Ответ на: комментарий от anonymous

Там просто принципиально отказались от этого. В OCaml откуда и содран вывод типов раста возвращаемое значение без проблем выводится.

Да. Поэтому приводить раст как язык с хорошим выводом типов, как минимум странно.

let square x = x * x
fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Да. Поэтому приводить раст как язык с хорошим выводом типов, как минимум странно.

Ну вывод вполне хороший на уровне того же OCaml, но сильно ограниченный, только внутри функций. В том же немерле вроде такое же ограничение было.

anonymous
()

да сколько угодно

auto dfs(const std::vector<std::vector<int>>& graph, int v, int p) {
  for (auto to: graph[v]) 
    if (to != p) 
      dfs(graph, to, v);
}

либо заменить auto на void, либо дописать -> void после сигнатуры

Lrrr ★★★★★
()
Ответ на: комментарий от anonymous

релевантный пример кода для топикстартера. А если тебе, дурачок, тут что-то не понятно - иди читай книжки по C++

Lrrr ★★★★★
()
Ответ на: комментарий от anonymous

Скажи это какому-нибудь GHC и хаскелю, там тупняк компилятора обычное дело, когда он не справляется с дюжей полиморфностью вида a -> a -> a

Ну тут как бы подразумевался с++ во-первых, во-вторых как не крути это все равно баг компилятора, так как он должен справляться даже с дюжей полиморфностью.

yetanother ★★
()
Ответ на: комментарий от Lrrr

Вычисление типа на Тьюринг-полной машине обломается на проблеме останова.

anonymous
()
Ответ на: комментарий от yetanother

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

К тому же полиморфизма в бездарной скриптухе типа хаскеля не существует в принципе. Весь код там реально мономорфный, типизированный подтипом. А какие-то потуги получить иногда чего-то большего в каких-то редких случаях - это не вывод типов.

Поэтому в скриптухе это не является багой. Это является базовым её свойством. Ситуация примерно так же, что с каким-нибудь пистоном в какой-нибудь ideшке. Типизации нет, но какие-то потуги что-то получить предприняты. И в каком-то случае это работает, но во всех и даже большинстве случаев это работать не будет.

Потому что пистон и любая другая скриптуха - никак на типизацию не полагается. Это не статический язык.

anonymous
()
Ответ на: комментарий от cdshines

не выводит, хотя контекстной информации достаточно.

Ну как по мне это как раз ограничение реализации, вызванное нежеланием усложнять реализацию компилятора. Так-то ведь вся информация у компилятора есть.

Перефразирую свое утверждение - теоретически компилятор всегда способен вывести тип, на практике же есть различные ограничения, например в виде той же сложности реализации.

yetanother ★★
()
Ответ на: комментарий от yetanother

Ну как по мне это как раз ограничение реализации, вызванное нежеланием усложнять реализацию компилятора. Так-то ведь вся информация у компилятора есть.

Зачем ты повторяешь херню написанную идиотами? Никакой «нужной информации» в контексте не существует. Обезьяна просто тупая. Там может быть хоть vector хоть vector.

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

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

Обезьяна просто тупая и «думает»(хотя думать это слишком сильно для неё), что vector в С++ это какое-то интерфейс из какой-то говноскриптухи. Но это не интерфейс. Это полностью полиморфный тип.

Поэтому vec может быть преобразован в vec без каких-либо проблем.

anonymous
()
Ответ на: комментарий от fsb4000

В D так можно уже давным давно можно делать:

auto square(uint num) {
    return num * num;
}

компилятор сам выводит тип функции. Думаю, говорить, что это очень удобно, особенно в метапрограммировании, не нужно?

При чем выводит также если есть несколько точек выхода из функции

auto square(long num) {
    if (num < 0)
        return num * num; // здесь возвращаем long

    return 0.0; // здесь возвращаем double
}

// Проверяем что типом результата функции является double
static assert(is(typeof(square(0L)) == double));

Компилятор D прекрасно понимает, что если из функции может вернуться и значение типа long и значение типа double, то типом результата должен быть именно double. Если же типы не могут быть неявно сконвертированы в общий тип (типа int и string), тогда возникает ошибка компиляции конечно.

Дарю идею.

Идея уже много лет реализована

yetanother ★★
()
Ответ на: комментарий от anonymous

Ну тут как бы с точки зрения компилятора ему суют incomplete type. С точки зрения кодера ему хочется чтобы компилятор механически дополнил этот самый incomplete type. Отбросим ленивых кодеров в сторону и признаем, что такая фича компилятора полезна в метапрограммировании, поскольку упрощает код и повышает его читабельность, но сложность реализации компилятора возрастает.

Поэтому тут и он прав, и ты. Тут кто с какой точки зрения смотрит.

yetanother ★★
()
Ответ на: комментарий от yetanother

С точки зрения кодера ему хочется чтобы компилятор механически дополнил этот самый incomplete type.

Нет, ещё раз повторю - это так не работает. Вывести здесь тип невозможно, потому как запить с ТЗ системы типов неоднозначна.

что такая фича компилятора полезна в метапрограммировании,

Абсолютно бесполезна. При наличие подобной херни система типов в недоязычке будет настолько примитивной, что никакого метапрограммирования у тебя в принципе не будет.

К тому же в данном случае однозначная запись return {}; - работает. И никакой vector{} там не нужен.

Поэтому тут и он прав, и ты. Тут кто с какой точки зрения смотрит.

Нет, здесь сектант просто нажрался пропаганды и перепутал скриптуху с реальностью.

В его скриптухе это выглядит так:

interface vec<T> {
  ...
}

vec<int> () { return vec{}; }


В связи с тем, что vec не полиморфен. Эта запись, которая vec{} - означает vec<any>{}. Тип T вообще ни на что не влияет. И vec может быть преобразован к чему угодно.

Очевидно про какой-либо полиморфизм в рамках подобной скриптухе ты можешь забыть. И эта обезьяна просто настолько тупая, что не может осознать ничего сложнее примитивности его бездарной скриптухи.

anonymous
()
Ответ на: комментарий от anonymous

однозначная запись return {}; - работает

Причем тут вывод типов? Тут банальный value initialization для пустого init list

anonymous
()
Ответ на: комментарий от anonymous

Причем тут вывод типов?

Притом.

Тут банальный value initialization для пустого init list

Нет. Для инициализации необходимо знать тип инициализируемого. Просто так инициализировать непонятно что нельзя. Какой именно там вид инициализатора - ничего не значит.

anonymous
()
Ответ на: комментарий от dimgel

Я имел дело с Nemerle. Те же грабли.

Тут проблема такая, что ООП-языки почти все поголовно вводят перегрузку функций (в Аде вообще до предела довели эту идею). А с перегрузкой такая история, что она сильно мешает выводу типов. Вот, и хотели как лучше, а получилось как всегда.

А перегрузка типов существует даже в хаскеле. Там иногда без аннотаций тоже не обойтись.

dave ★★★★★
()
Ответ на: комментарий от anonymous

Для инициализации необходимо знать тип инициализируемого

Который заранее известен по декларации самой функции - полный тип возвращаемого типа указан - него выводить.

anonymous
()
auto f(auto x) {
  return x;
}

auto x = f(x);

в общем случае компилятор не может вывести тип по выражению слева от =.

более простой вариант:

auto f();

int x = f();

anonymous
()
Ответ на: комментарий от cdshines

ты запутал компилятор

return {}
anonymous
()
Ответ на: комментарий от cdshines

ты наверное путаешь ctad с deduction guides. ctad - это std::tuple t(2, 3.5, "abc"s). советую почитать что-нибудь про с++.

anonymous
()
Ответ на: комментарий от yetanother

теоретически компилятор всегда способен вывести тип, на практике же есть различные ограничения, например в виде той же сложности реализации.

А почему такой язык как например lisp всегда выводит типы без ошибок?

Lzzz
() автор топика
Ответ на: комментарий от anonymous

Так нельзя

да? а мне множно.

template <class T>
auto f(T x) {
  return x;
}

эквивалентно

auto f(auto x) {
  return x;
}

потому что компилятор использует те же правила которые используются для инстанциирования шаблонов.

https://godbolt.org/z/n5xbha

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.