Войти
ПрограммированиеФорумГрафика

Вопрос по C++.

Страницы: 1 2 39 10 Следующая »
#0
6:13, 2 мая 2019

Я уже сто лет как пишу на C++ и думал, что я хорошо знаю матчасть. Но недавно обнаружил, что я безнадежно отстал от жизни. Встретил вот такое выражение и впал в ступор:

auto DispatchRays = [&](auto* commandList, auto* stateObject, auto* dispatchDesc) 

Ну что такое auto я знаю. Вроде как это указание препроцессору (?) использовать тип правого аргумента. Но в данном случае определен только первый параметр - commandList. Переменные stateObject и dispatchDesc до того нигде не появлялись, т.е. они тут и определены. Что тогда значит auto если у них еще нет типа? Ну и вишенка на торте - [&].  А это что за зверь? По идее это функция, но не факт. Есть тут знатоки языка а то я что-то забуксовал...


#1
(Правка: 6:28) 6:25, 2 мая 2019

san
тут не знатоки нужны, а базовое знание стандарта, которому уже почти 10 лет: https://docs.microsoft.com/en-us/cpp/cpp/lambda-expressions-in-cpp?view=vs-2019

> Что тогда значит auto если у них еще нет типа?
тип определяется при инстанцировании лямбды, а не при её объявлении

#2
6:29, 2 мая 2019

Suslik
> почти 10
Меньше, это вроде в 14-м стандарте добавили.

san
> Что тогда значит auto если у них еще нет типа?
Это синтаксический сахар, за введение которого в язык надо палками бить авторов этого.
Это, на самом деле, шаблон лямбды. auto подставится при первом использовании этой лямбды. Аналог у этого следующий:

struct Lambda
{
  template<typename A, typename B, typename C>
  void operator()(A* a, B* b, C* c){}
};
#3
6:35, 2 мая 2019

Компиляторы под этот стандарт стали общедоступными и повсеместными лет пять назад, а до этого был сначала проект, а потом стандарт.
Почти все появилось в 11м стандарте, т.е. датированном 2011м годом, но это не значит что тогда же оно стало применимым на практике. В 14м лишь доработки 11го. Изучается и обсуждается очень давно, явно поболее 10 лет, как бы не все 20.

#4
(Правка: 6:53) 6:50, 2 мая 2019

Suslik
> тут не знатоки нужны, а базовое знание стандарта, которому уже почти 10 лет:
Ну поскольку я изучал C++ где-то 25 лет назад, то мне простительно. :)

Panzerschrek[CN]
> Это, на самом деле, шаблон лямбды.
Ну осталось понять что такое лямбда... Хотя если это структура, до догадаться можно.

> Это синтаксический сахар, за введение которого в язык надо палками бить авторов этого.
Это горячо поддерживаю! И раньше синтаксис C/C++ был малочитаем из-за игр с ссылками на функции, так теперь он вообще начинает напоминать китайский алфавит. Началось с темплейт и дальше понеслось. Все эти заклинания похоже уже вышли из под контроля.
Кстати один из косяков разработчика языка (ноги растут из Си), это путаница с вызовом функций и инициализацией структур. Зачастую понять что имеется ввиду крайне сложно. В данном случае далее идет вызов:

DispatchRays(m_fallbackCommandList.Get(), m_fallbackStateObject.Get(), &dispatchDesc);
Выглядит как вызовы функций, хотя скорее всего это инициализация.
Для знатоков могу привести весь код, наслаждайтесь!
void D3D12RaytracingHelloWorld::DoRaytracing()
{
    auto commandList = m_deviceResources->GetCommandList();
    
    auto DispatchRays = [&](auto* commandList, auto* stateObject, auto* dispatchDesc)
    {
        // Since each shader table has only one shader record, the stride is same as the size.
        dispatchDesc->HitGroupTable.StartAddress = m_hitGroupShaderTable->GetGPUVirtualAddress();
        dispatchDesc->HitGroupTable.SizeInBytes = m_hitGroupShaderTable->GetDesc().Width;
        dispatchDesc->HitGroupTable.StrideInBytes = dispatchDesc->HitGroupTable.SizeInBytes;
        dispatchDesc->MissShaderTable.StartAddress = m_missShaderTable->GetGPUVirtualAddress();
        dispatchDesc->MissShaderTable.SizeInBytes = m_missShaderTable->GetDesc().Width;
        dispatchDesc->MissShaderTable.StrideInBytes = dispatchDesc->MissShaderTable.SizeInBytes;
        dispatchDesc->RayGenerationShaderRecord.StartAddress = m_rayGenShaderTable->GetGPUVirtualAddress();
        dispatchDesc->RayGenerationShaderRecord.SizeInBytes = m_rayGenShaderTable->GetDesc().Width;
        dispatchDesc->Width = m_width;
        dispatchDesc->Height = m_height;
        dispatchDesc->Depth = 1;
        commandList->SetPipelineState1(stateObject);
        commandList->DispatchRays(dispatchDesc);
    };

    commandList->SetComputeRootSignature(m_raytracingGlobalRootSignature.Get());

    // Bind the heaps, acceleration structure and dispatch rays.    
    D3D12_DISPATCH_RAYS_DESC dispatchDesc = {};
    {
        D3D12_DISPATCH_RAYS_DESC dispatchDesc = {};
        commandList->SetDescriptorHeaps(1, m_descriptorHeap.GetAddressOf());
        commandList->SetComputeRootDescriptorTable(GlobalRootSignatureParams::OutputViewSlot, m_raytracingOutputResourceUAVGpuDescriptor);
        commandList->SetComputeRootShaderResourceView(GlobalRootSignatureParams::AccelerationStructureSlot, m_topLevelAccelerationStructure->GetGPUVirtualAddress());
        DispatchRays(m_dxrCommandList.Get(), m_dxrStateObject.Get(), &dispatchDesc);
    }
}

#5
(Правка: 6:55) 6:53, 2 мая 2019

san
> Ну осталось понять что такое лямбда... Хотя если это структура, до догадаться
> можно.
для этого достаточно почитать ссылку, которую я уже привёл, или самостоятельно найти любую другую в гугле по запросу "c++ lambda"

san
> > Это синтаксический сахар, за введение которого в язык надо палками бить > авторов этого.
> Это горячо поддерживаю!
так всегда было и будет. C++ будет развиваться, хотите вы того или нет. вам остаётся либо успевать, либо тихонько отходить к пенсии.

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

#6
6:56, 2 мая 2019
Suslik
Panzerschrek[CN]
> Это синтаксический сахар, за введение которого в язык надо палками бить авторов
> этого.
+++++++++++++
#7
(Правка: 7:15) 7:07, 2 мая 2019

Suslik
> ля этого достаточно почитать ссылку, которую я уже привёл, или самостоятельно найти любую другую в гугле по запросу "c++ lambda"
Спасибо, разберусь. Если знать где копать далее уже просто.

> так всегда было и будет. C++ будет развиваться, хотите вы того или нет
Не факт. Зачем корежить язык? Все это можно реализовать штатными средствами, которые устаканились 20 лет назад. Или уже не насилуйте C++ и переходите на что-то принципиально другое. Правда пока ничего лучше еще не придумали.

>код, кстати, который ты привёл, предельно прозрачен, мне кажется, его можно даже понять
Да ты что? Правда что ли? Я пытаюсь. :)

Проблеммы было две - непонятка с [&] и auto на еще не созданные типы (согласись, это вообще-то хрень какая-то), но спасибо вам, теперь начинаю понимать как это работает. А второе хуже - в C++ часто фиг поймешь где функция а где инициализация. Я далеко не фанат Паскаля, скорее наоборот, но там это сделано все же как-то строже.

#8
(Правка: 7:17) 7:15, 2 мая 2019

san
> А второе хуже - в C++ хрен поймешь где функция а где инициализация. Я далеко не
> фанат Паскаля, скорее наоборот, но там это сделано все же как-то строже.
а я считаю, что наоборот — все эти детские травмы про "я не понимаю, где функция, где перегруженный оператор ()", нанесённые раньше, как раз шли из-за того, что вместо нормальных лямбд приходилось реализовывавать то же самое посредством функторных ужасов вроде #2. результирующий код часто используется снаружи точно так же, но внутри реализация будет гораздо чище и понятнее при использовании более сильных языковых конструкций, чем при использовании разного рода хаков функторов и перегруженных операторов вроде скобок и запятых, которые считались нормой до 0x стандартов.

#9
(Правка: 7:43) 7:32, 2 мая 2019

Suslik
> а я считаю, что наоборот — все эти детские травмы про "я не понимаю, где функция, где перегруженный оператор ()", нанесённые раньше, как раз шли из-за того, что вместо нормальных лямбд

Если ты пишешь код для себя, то можно делать все что угодно. Я знал одного программиста, который писал код в одну сполошную строчку - т.е. переводы строк формировались размером листа. Пробелы он принципиально игнорировал. Прочитать это было совершенно невозможно, но он "так видел". Хотя компилятор это жевал на ура. (Кстати неплохой программист не смотря на эти закидоны).

В данном случае я говорю о понятности кода для стороннего наблюдателя. Я стал разбираться с рейтресингом и налетел на эти грабли. Это вроде как пример для обучения начинающих. Эти языковые изыски ничего не дают к функциональности, но превращают код в квест. Вопрос - а нафига? Зачем вместо простого примера показывать свою крутизну перед детским садом?
Я как-то жил 25 лет без этих выпендронов и вроде не сильно страдал от их отсутствия. Кутизна программиста все же не в наворотах кода, а в алгоритмах которые ОН придумал и реализовал. А все остальное это глупое меряние пиписьками. Экономия 10 строк кода не стоит потерь времени тех, кто пытается понять технологию. Не код.

#10
(Правка: 7:43) 7:38, 2 мая 2019

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

> Я как-то жил 25 лет без этих выпендронов и вроде не сильно страдал от их отсутствия.
примерно такие же басни я слышал от стариков про перфокарты и ферритовые кольца. даже если ты действительно так считаешь, я бы постеснялся на твоём месте в этом признаваться.

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

#11
7:56, 2 мая 2019

Suslik
>примерно такие же басни я слышал от стариков про перфокарты и ферритовые кольца.

Ну перфокарты я застал. И мне как-то упал на ногу накопитель в 14 МБ весом 95 кг. Было больно. Сейчас у меня под столом стоит комп с общим обьемом дисков в 40 ТБ. Но я как писал программы, так и пишу. Правда тогда я писал на фортране рассчет термодинамики при посадке Бурана, а сейчас у меня два шлема VR и пишу я виртуальный интерфейс создания фрактальных вселенных. Ну да, не всегда успеваю за полетом мировой мысли. Нет у меня времени следить за идеями развития языка, не теоретик я. Пока мне инструмента хватает я не дергаюсь. Вот узнал про лямбду, может буду использовать. Или нет. Но в любом случае это не для примеров освоения технологии. Пример должен быть максимально простым. Точка.

ПОтом Я говорю не об перегруженном оператора, а о конструкции типа:
a(10, 20);
'a' это функция или структура? Ты это можешь определить просто глядя на код, или надо искать где 'a ' определена? А если она вообще не определена, как в моем примере? Это было заложено 40 лет назад, но было сделано неправильно. Ритчи лопухнулся, точнее сделал на скорую руку. А мы с этим живем.

#12
(Правка: 8:08) 8:04, 2 мая 2019

san
> Зачем вместо простого примера показывать свою крутизну перед детским садом?
Лямбда в данном случае делает код проще. Если ты поймешь как работают лябды и научишься ими пользоваться - сомнений, что данный код проще, не останется.

p.s. Меня кстати больше напрягают auto внутри вот этих скобочек:
(auto* commandList, auto* stateObject, auto* dispatchDesc)
Потому что конкретно тут я бы предпочел явное указание типов.
p.p.s. Это касается только auto как параметров функции, а не самой лямбды auto DispatchRays. Тут как раз auto в тему.

#13
8:05, 2 мая 2019

ИНтересно, топикстартер уже дошел до move-semantics и всех этих игр с r-value  reference?

#14
8:09, 2 мая 2019
Dmitry_Milk
Я почему-то думаю, что там даже не то что move-semantics, там даже смартпоинтеров нет, и он делает new delete ручками.
Страницы: 1 2 39 10 Следующая »
ПрограммированиеФорумГрафика