Обновить
4
Viktor Pti@Qbit

Пользователь

4
Подписчики
Отправить сообщение
> В итоге получится, что требование «только стандартная библиотека, ну максимум буст» является неудачной попыткой получить фору

Да нет, просто опасался получить решение в одну строку вида superlib::do_some_magic(), где функция берётся из какой-то хитрой никому не известной специализированной библиотеки. А Qt ок, почему нет.
> Что вам не понятно в этом решении? (кстати, извиняюсь за опечатку: там не хватает открывающей скобки "(" после «fromLocal8Bit»)

Мне всё понятно, даже синтаксические ошибки могу в уме исправлять :) Но время на восприятие плюсового намного выше, чем у аналогичного C#-кода. И дело не только в приведённых кратких фрагментах, я говорю на основании опыта промышленного использования C++ (тогда ещё без 0x, но уже с блэкджеком) и C#. В последнем благодаря Linq обработка коллекций любых типов выглядит одинаково и идиоматично, легко узнаваема.

А ваш код вполне нормален, где-то недалеко от максимума выразительности, которую можно выжать из языка. Правда, я хотел бы увидеть хоть какие-то ФВП общего назначения, получающие лямбды (предикаты фильтрации, сравнения, селектор, etc), но сходу предложенный пример, как оказалось, решился частными библиотечными функциями для работы со строками. Ну и бог с ним.
> При наличии единожды установленного Qt оверхед 0 мегабайт. Я вам даже больше скажу: при наличии единожды установленного $anything оверхед будет 0 мегабайт :)

Так а в чём тогда цимес уделять столько внимания размерам дистрибутивов рантаймов?

> Просто предкомпилированные пользовательские библиотеки весят 55 мегабайт в распакованном виде (и 18 мегабайт в виде тупого ZIP-а, сколько будет весить инсталлятор прикиньте сами, я не в курсе, какой там алгоритм сжатия используется)

Ещё можно приплюсовать размер плюсового рантайма (vcredist*.exe, Visual C++ 2010 Runtime Redistributable Package), его ж у пользователя тоже может не быть. И в итоге что получится? А хрен его знает, мне абсолютно лень считать, но да — мегабайтов 30 выиграет у .NET'а, HUGE SUCCESS!
> В итоге первый пример легко и непринуждённо решается с помощью Qt ничуть не сложнее, чем на шарпе

Легко и непринуждённо, ничуть не сложнее? :) Хоть в одном из предложенных C++-вариантов навскидку (человеком, впервые читающим код) вычисление декомпозируется на стандартные ФВП: фильтрация—сортировка—проекция—итерация… (аггрегация, свёртка, zip, unfold, etc)? Подобные Linq-запросы на C# пишутся секунд за 30 без циклов, условных операторов и прочей императивщины с изменением состояний. C++ по скорости написания кода и скорости его восприятия даже близко не стоит.

> второй тоже недалеко от этого ушёл.

Путём решения фунарг-проблемы на ручной тяге?

> Собственно, если вы переформулируете своё заявление как «есть вещи, над которыми мне приходится корпеть в плюсах», то все вопросы моментально отпадут.

Это не ко мне, изначально не я формулировал это заявление. Я просто привёл пару простых примеров.
> Это как это мы так предполагаем, если мы только что сами ясно написали, что данная лямбда осуществляет захват по значению и оригинал менять не может?

Ну, а надо по ссылке!
> и спокойно меняем захваченное значение ибо оно внутри объекта, реализующего лямбду.

А если мы вызываем assignNewValue(31) перед выходом из Foo() и предполагаем, что вызов таки изменит нашу локальную переменную valueToBeClosed?
> Вот только если вы захотите распространять свою программу на Qt, можете вместе с ней кинуть пару нужных dll и всё.

Тут тройку dll, там пару тех же dll…

> А на сишлаке хочешь — не хочешь, а весь .NET Framework, будь добр, поставь!

В современных операционках от Microsoft фреймворк уже предустановлен, т.е. идёт как часть системы. В операционках 10-летней давности фреймворка может и не быть, но, как правило, у клиентов он всё равно уже установлен с другим софтом типа GTA IV или AutoCAD.
> Тогда зачем это спрашивать у меня, нужно самому писать и говорить так и так, а не троллить

Я никого не тянул за язык, просто deMonteCristo спросил «пример… вещей, над которыми надо корпеть в плюсах и совсем не надо в шарпе». Я просто предоставил два примера, с меня и взятки гладки. Какой троллинг, прости господи?

> В C# нет operator() и ваше решение обходит это

Это как раз наоборот, в C++ нет первоклассных функций и не решена upwards funarg problem, так что обходят кривым способом с помощью operator ().

> Конечно не знали до текущего момента.

Это грязные инсинуации, благородному дону не пристало. Не только знал, но ещё до публикации задачи написал proof-of-concept реализацию на C# и вариант на C++0x, воспроизводящий UB.

Исходный псевдокод:
Foo : () → (int → int) = 
() ↦ {
  valueToBeClosed : int = 3;
  assignNewValue : int → int =
    value ↦ {
      result : int = valueToBeClosed;
      valueToBeClosed = value;
      return result;
    }
  return assignNewValue;
}


Подстрочный перевод на C#:
static Func<int, int> Foo()
{
    int valueToBeClosed = 3;

    Func<int, int> assignNewValue = value =>
    {
        var result = valueToBeClosed;
        valueToBeClosed = value;
        return result;
    };

    return assignNewValue;
}


Аналогичный вариант на C++, содержащий скрытую ошибку:
std::function<int (int)> Foo()
{
    int valueToBeClosed = 3;

    auto const assignNewValue = [&] (int value) -> int
    {
        auto const result = valueToBeClosed;
        valueToBeClosed = value;
        return result;
    };

    return assignNewValue;
}
>>> Такие замыкания в паре с мутабельной лямбдой используют в Scheme для имитации объектов.

>> А схемщики считают, что это объекты в ООП служат для имитации замыканий.

> Схемщиков тута нету.

Какая разница, есть ли тута схемщики. Я имел в виду слова (емнип) Нормана Адамса «Objects are a poor man's closures», которые считал достаточно известными.
> Что ожидалось, понятно: «Так и быть, можно Boost, Qt и Loki.», а было представлено простое решение, минимально отличающееся от псевдокода, но сохранить лицо надо было.

Какое «сохранить лицо», «ожидалось» и «программист на C#, который С++ не видел»? Я прекрасно знаю, как подобный код пишется на C++. Упомянув библиотеки, я всего лишь имел в виду, что, раз уж в C++ нет первоклассных функций, допускается использовать библиотечные функторы из boost, Loki, std::tr1 или вот из нового std.

> В момент, когда такая задача возникла

Вы не улавливаете контекста. Я имел в виду, что если у вас уже есть функция с int valueToBeClosed = 3;, то вы не можете просто добавить замыкание, не меняя его контекст. Вы должны не забыть превратить окружение (valueToBeClosed) в ссылку (в общем смысле, не C++) на нестековое значение и передать её по значению.

> Это решение какой-то задачи, не самое лучше.

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

> В C# зло так делать, если нужно вернуть объект с состоянием — возвращай объект с состоянием, а не делай грязные лямбды на пустом месте.

Ерунда. Зачем мне передавать объект с состоянием, если я хочу это состояние скрыть от пользователя? Получится объект с одной функцией и недоступным пользователю состоянием. Так почему бы сразу не вернуть одну лишь функцию, зачем плодить сущности?
> Такие замыкания в паре с мутабельной лямбдой используют в Scheme для имитации объектов.

А схемщики считают, что это объекты в ООП служат для имитации замыканий.

> ideone.com/qnbrm

Вот это и называется «вещами, над которыми надо корпеть в плюсах и совсем не надо в шарпе». Ты не можешь просто замкнуть переменную по ссылке. В момент, когда такая задача возникла, тебе надо изменить окружающий код, заморачиваться с передачей по значению ([=]) ссылки (указателя shared_ptr). А без этого программа скомпилируется без всяких предупреждений, и, самое страшное, не исключено что при определённых условиях UB будет проявляться так, что создаст видимость правильной работы.
> И да, использованная здесь QtCore вполне укладывается в «без фанатизма» и «по минимуму» — она весит чуть более 2.5 мегабайт.
А сколько будет весить рантайм для вашего решения? ;)


Какой-то странный подход, сравнивать среду выполнения и библиотеку.
1) Дополнительных библиотек в моём коде не требуется, так что при наличии единожды установленного .NET 4.0 оверхед 0 мегабайт.
2) Если учитывать вес рантайма, то полный дистрибутив dotNetFx40_Full_x86_x64.exe весит 48.1 Мб, достаточный дистрибутив dotNetFx40_Client_x86_x64.exe — 41.0 Мб. Если верить офсайту Qt, то даже без SDK (который за гигабайт), просто предкомпилированные пользовательские библиотеки весят от 200 Мб.
Хорошо, пусть решение. Так вы можете предоставить код решения на C++? Так и быть, можно Boost, Qt и Loki.

Требуется что-то вроде такого решения на псевдокоде:
Foo : () → (int → int) = 
() ↦ {
  valueToBeClosed : int = 3;
  assignNewValue : int → int =
    value ↦ {
      result : int = valueToBeClosed;
      valueToBeClosed = value;
      return result;
    }
  return assignNewValue;
}

Использование:
foo : int → int = Foo();
WiteLine( foo(21) ); // 3
WiteLine( foo(42) ); // 21
>> Библиотеки решают. :-)
> Дык о чём и речь :)

Можно задачу без библиотек. Например: вернуть из первой функции другую функцию, замыкающую по ссылке локальную переменную первой функции.
File.ReadAllLines("test.txt")
    .Where(line => line.Split(' ').Length > 3)
    .OrderBy(s => s)
    .Run(Console.WriteLine);
> Давайте, для интереса, напишем решение этой задачи: вы на c#, я на c++ и сравним результаты. :)

Давайте.

> Я уже указывал в комментариях, что не нужно отказываться от мощи чудесный фреймворков и библиотек.

Ок, только без фанатизма; скажем, можно Boost. Но желательно также приложить вариант, ограничивающийся только стандартной библиотекой.

> Подобного говна можно найти про любой язык. :)

Но только про C++ его так много.
> Я мало знаком с C#, но можно пример? :) Ну, в смысле, вещей, над которыми надо корпеть в плюсах и совсем не надо в шарпе?

«Вывести на экран все строки текстового файла, в которых более трех слов, отсортированные по алфавиту.»

> вещей, над которыми надо корпеть в плюсах...

The Dark Side of C++
C++ FQA Lite
> не вижу ничего плохого в шаблонах.

image
Не говоря уже о том, что в финализаторе нельзя обращаться к другим финализируемым объектам, так как порядок вызова финализаторов не определён: «Specifically, you must know that any code you call from within a Finalize method does not use any other object that could have already been finalized.» © Richter

И вообще: «If you’re familiar with C++, you’ll notice that the special syntax C# requires for defining a Finalize method looks just like the syntax you’d use to define a C++ destructor. In fact, the C# Programming Language Specification calls this method a destructor. However, a Finalize method doesn’t work like an unmanaged C++ destructor at all, and this has caused a great deal of confusion for developers migrating from one language to another.
The problem is that developers mistakenly believe that using the C# destructor syntax means that the type’s objects will be deterministically destructed, just as they would be in C++. However, the CLR doesn’t support deterministic destruction, preventing C# from providing this mechanism.» © Richter
> предполагается ответ с try...catch

Это неправильный ответ. Для usage-ошибок не надо использовать try...catch.

> более половины пишут что всегда анализируют делитель

И правильно делают. Это не от незнания про исключения, а от умения ими не пользоваться в неподходящих местах.

> Я проводя собеседования на вакансию программера С++ сильно удивился, что про исключения знает менее чем каждый второй соискатель.

Вы и сами бы не прошли собеседования на джуниора.

> предполагается ответ с try...catch

Правильный ответ (с учётом рассуждений про баррикады) может быть примерно таким (на C#).

Вызываемый код:
private double DivUnsafe(double a, double b)
{
Debug.Assert(!/*корректное сравнение b с 0.0*/);
return a / b;
}

public double Div(double a, double b)
{
// Не допускается выбрасывание из библиотеки ZeroDivisionException,
// NullReferenceException и тому подобных исключений.
if (/*корректное сравнение b с 0.0*/)
{
throw new ArgumentException(...);
}
return DivUnsafe(a, b);
}

В библиотечном коде (по «нашу сторону» баррикад) всегда вызываем DivUnsafe, контекст вызова всегда можем контролировать. Пользовательскому коду (на корректность которого мы не можем прямо влиять) предоставляется Div.
Неправильный вызывающий код:
try
{
c = Div(a, b);
}
cactch (ArgumentException ex)
{
// Обработка ошибки, например:
throw new MyBusinessLogicException(..., a, b, ex);
}

Правильный вызывающий код:
if (/*корректное сравнение b с 0.0*/)
{
// Обработка ошибки, например:
throw new MyBusinessLogicException(..., a, b);
}
с = Div(a, b);

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность