- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
void inline WriteXY(int X, int Y, byte szText, WORD fColor = 0x01F) {
DWORD cWritten;
COORD ptCoord = {X - 1, Y - 1};
gotoxy(X, Y);
cout << char(szText);
cout.flush();
FillConsoleOutputAttribute(hStdOut, fColor, 1, ptCoord, &cWritten);
return;
}
void inline WriteXY(int X, int Y, string szText, WORD fColor = 0x01F) {
DWORD cWritten;
COORD ptCoord = {X - 1, Y - 1};
gotoxy(X, Y);
cout << szText.c_str();
cout.flush();
FillConsoleOutputAttribute(hStdOut, fColor, strlen(szText.c_str()), ptCoord, &cWritten);
return;
}
strlen от std::string тоже ок
Но оно имеет смысл, если строка содержит нули.
странно что заминусовали пост
передача значения по умолчанию была актуальна при передаче через регистры или через стек при вызове функции
в случае структур программист уже сам должен был решить, будет ли он копировать её целиком на стек, или передаст указатель
это потом уже в С++ появились объекты объекты объекты, копирование которых может быть затратным, а с указателями тот еще геморрой - добавили ссылки, чтобы компилятор за программиста подставлял указатели и позволял внутри использовать объект как объект
Ну и что, кто мешает компилятору const& для типов, занимающих 4-8 байт, трактовать, как передачу по копии, то есть передавать в регистрах или стеке?
Я больше скажу, даже просто & в Аде передаётся через регистры и стек, с копированием изменённого значения обратно при выходе из функции. Это заметно при использовании исключений - при исключении обратного копирования не происходит, в стандарте это даже сказано. Вообще нефиг логику на исключении строить.
сделать
и думать, когда конкретно он изменит свое значение
и как же непосредственно контролировать то, что переменная обязана быть передана по копии или по ссылке?
ты же понимаешь, что передавая std::string str я имею полное право поменять значение в этой str внутри функции, не затрагивая её оригинал, передавая по const & я на уровне ошибок компиляции могу отслеживать запрет на запись в нее, а передавая по & точно быть уверенным, что я в нее могу и буду писать
Use keywords 'in out inout', Luke!
В C# это делается так:
передача по значению in и передача по const & тоже in
и что, гцц уже понимает in out и других телепузиков?
Ну вот пусть компилятор определит лучший способ передачи.
Как видите, С++ будет не оптимально использовать эту конструкцию для типов малого размера и в С++ текущего стандарта это никак не учтено.
>и что, гцц уже понимает in out и других телепузиков?
GCC кроме телепузиков ничего не понимает.
я всё равно не понял, как добавление in или забывание о const & может помочь в:
я хочу по значению и буду по значению, хочу по конст ссылке и буду по конст ссылке, в одном случае я имею право менять значение, оно на стеке и никому не мешает, а во втором если что компилятор тупо не даст мне ничего присвоить такому параметру
ну а касательно того, что что то там неоптимально передается в стек при ссылке на чар - без оптимизации потери не слишком велики - на одну операцию больше
но при этом такая операция очень легко оптимизируется
-fipa-sra
Perform interprocedural scalar replacement of aggregates, removal of unused parameters and replacement of parameters passed by reference by parameters passed by value.
Enabled at levels -O2, -O3 and -Os.
т.е. нужды в оптимизации такого на уровне языка нет никакой
это дело оптимизации компилятором, более того, такая оптимизация включена в -O2 - самом распространенном режиме релизной сборки
если тебе понадобится передать инт по значению, и ты уверен что эта одна лишняя строка ассемблера реально снизит тебе на 50% производительность, и ты не хочешь зависеть от оптимизаций - не пользуйтся шаблоном с T const &, а напиши отдельно тело f(int)
практика показывает, что это не тот оверхед, о котором стоит беспокоиться
давай лучше поговорим об оверхедах ады, которая такая умница сама решает как ей передать параметры и еще и не накатывает изменения пока функция не завершится
И ещё 100500 копипаст в отдельных функциях на все типы, что маленькие и вы планируете использовать. Крестушки очень любят костыли, копипасту и ручную работу.
Кресты провоцируют на дублирование кода. Я об этом уже говорил в теме про крестошаблоны, которые не могут повторить свою логику работы в рантйаме.
> давай лучше поговорим об оверхедах ады
Давай. В ней нет move-конструктора, мне это печально :(
по сути адовские генерики легко имплементируются в С++ с помощью void *
Расскажи.
> по сути адовские генерики легко имплементируются в С++ с помощью void *
Как?
У нас один шаблон и на время компиляции и на время рантайма, и когда компилятор может - он раскрывает шаблон полностью, избавляя от переголовы. А в крестах надо и шаблон для компилятора, и просто код, чтобы та же логика обрабатывалась самой программой.
template <class T>
void f()
{
typedef some_type typename T::some_type;
T::static_call();
if (x < T::enum_value1) ....;
T.method_call(T.field);
T variable_of_T1, variable_of_T2;
sizeof(variable_of_T1);
// etc etc etc
}
template <class T>
class Z: public templated_base<T> {
// use T here as you want too
};
можно даже сделать специализации, имея в компайл-тайме тьюринг-полноту
теперь давай посмотрим на райнтайм-шаблонное программирование от ады:
мы передаем в шаблон лишь числа или тип, причем использование этого типа резко ограничено управлением кусков памяти, занимаемых этим типов, даже доступ к полю структуры резко ограничен
т.е. фактически мы такое шаблонное программирование можем имплеменировать не то что на С++, а на С - на педивикии рассмотрен классический пример "контейнер элементов типа Т"
используя просто void * и размер элемента мы можем безусловно построить такой контейнер - нам не нужно ничего знать о типе Т кроме его размера
вот такие вот рантайм-шаблоны в аде, всего лишь слабый синтаксический сахар вокруг void *, позволяющий делать минимальные проверки типов и кастинг за программиста
Крестопроблемы.
В Аде в шаблон можно передавать или тип, или любое значение любого типа, или функцию, или модуль.
Через передачу функции можно делать специализации.
> используя просто void * и размер элемента мы можем безусловно построить такой контейнер - нам не нужно ничего знать о типе Т кроме его размера
Да, можем, логика работы будет такая же. А скорость работы - нет. Функция сортировки на Си требует указатель на функцию сравнения. В Аде функция сравнения - это параметр шаблона, и он может заинлайниться, как и в крестах.
Твоя претензия вся придумана непойми откуда.
Ты решил, что если Ада может шаблоны во время работы программы, то не может при компиляции? Это в крестах так - код работает ЛИБО при работе программы, ЛИБО при компиляции, кресты не могут один и тот же код и при компиляции и при работе программы, это крестопроблемы.
ну так как мне получить в аде-шаблоне от типа Т доступ к полям этого типа?
к дефайнам этого типа? к методам этого типа? к константам этого типа?
овощи рожь вот это всё:
typedef some_type typename T::some_type;
T::static_call();
if (x < T::enum_value1) ....;
T.method_call(T.field);
я тебе подскажу - в аде этого нет, потому что невозможно в рантайме проверить, есть ли в типе Т тип, поле, метод, константа с таким именем
вот именно, функция сортировки на Си именно что == шаблону в аде
шаблону в аде ты передаёшь тип (размер элементов) и функцию сортировки, в Си то же самое, а то, где оно будет объявлено - в шапке <> или в параметрах, уже роли никакой не играет
и что там будет инлайниться - нереальный прирост в производительности, конечно, вот для чего нужны были генерики, сэкономить один колл и несколько операций заполнения стека перед вызовом
метапрограммирование да
Передать в шаблон функции GetA и SetA, которые устанавливают значение этого поля.
> вот именно, функция сортировки на Си именно что == шаблону в аде
Только скорость работы разная, потому что функция подставляется при компиляции.
> и что там будет инлайниться - нереальный прирост в производительности, конечно, вот для чего нужны были генерики, сэкономить один колл и несколько операций заполнения стека перед вызовом
метапрограммирование да
Это делается для типобезопасности и удобства, ващето, а не для того, чтобы рассказывать на форумах, что шаблоны тьюринг-полны, как брейнфак.
> я тебе подскажу - в аде этого нет, потому что невозможно в рантайме проверить, есть ли в типе Т тип, поле, метод, константа с таким именем
Зато можно в рантайме составить любую функцию GetA и SetA и передать её в качестве параметра шаблона.
как мне поможет функция GetA/SetA для доступа t.a = 100, передавая в шаблон либо struct1 или struct2? она тоже должна быть шаблонная?
ну так если я в первой функции не смог получить доступ к полю, значит и в SetA так же не смогу
я не понимаю этой идеологии
и еще понимаю, что врядли смогу сделать typename T::freaking_type z = 200; внутри своей шаблонной функции, ну это ладно
расскажи про SetA
my_template_type<struct1, set_a_for_struct1, set_b_for_struct1> a;
my_template_type<struct2, set_a_for_struct2, set_b_for_struct2> b;
ну чисто как в си, передаю параметрами указатели (&a, sizeof(int), set_a_for_struct1, set_b_for_struct1);
верно?
В Аде шаблоны, а не генерики.
вот и до тебя руки дошли
http://en.wikipedia.org/wiki/Generic_programming
ищи разделы Generics in Ada и Templates in C++
> Generics
> Templates
польза от полностью компайл-тайм шаблонов как раз в том, что в компайл-тайм шаблон раскроется для каждого из инстанциированных типов и скомпилируется как отдельная функция/класс с собственными адресами и точками входа
именно это и приводит к долгой компиляции в С++, однако именно это и позволяет делать в шаблонах с шаблонным типом всё, что угодно, а не лишь имплементировать десяток классических алгоритмов сортировки или контейнеров с постоянной передачей им (sic!) отдельных функций сравнения и сортировки
и именно поэтому дополнительный (оригинальный) шаблонный код в рантайме в С++ отсутствует - все используемые шаблоны уже проинстанциированы, а неиспользуемые - даже не слинкованы и отсутствуют в бинарнике
и именно поэтому рантайм-метапрограммирование либо скатывается в фуфельную обёртку над черными ящиками void * - да, всё так же быстро как и компайл-тайм, при этом экономия бинарника, но абсолютно никакой свободы,
либо становится очень дорогим, т.к. надо за каждым типом хранить очень много информации о непосредственно типе (имена, декларации) и вызывать исключения, когда передаваемый в рантайм-шаблон тип внезапно где то не удовлетворяет вызову var.field1(), потому что field1() в этом типе отсутствует
Обломись, в Аде так же, если есть возможность (тебе это 10 раз повторить?), т.е. если все параметры и функции известны при компиляции.
И в крестах один хрен. Только кресты обязывают, чтобы параметры были известны компилятору. Ада этого не требует, просто в таких случаях генерирует менее оптимальный код.
> или контейнеров с постоянной передачей им (sic!) отдельных функций сравнения и сортировки
Не с постоянной, и лишь при инициализации шаблона. Тебе всё равно придётся для каждого типа писать функцию сравнения, что в крестах, что в Аде.
> и именно поэтому дополнительный (оригинальный) шаблонный код в рантайме в С++ отсутствует
В Аде он тоже отсутствует, если его можно убрать. А если нельзя убрать, то Ада делает код, который уже делает обработку сам, в отличии от крестов, которые тупо запрещают это.
Вы, крестовики, считаете, что такие крутые шаблоны есть только в крестах, а при виде другого языка, который умеет делать то же самое, срёте кирпичами и сочиняете байки про то, что в нём якобы не так.
только мне не придется её таскать за собой при каждой инициализации шаблона, в который передается мой тип
ответь про SetA выше
я верно догадался?
Зачем ты инициализируешь шаблон 100500 раз для одного типа? Один раз инициализировал и используй 100500 раз.
> ответь про SetA выше
> я верно догадался?
О чём? Исключение при рантайме?
К сожалению, не так, наличие нужной функции сразу известно при компиляции, модифицировать классы на лету нельзя. Но можно вместо SetA передать в шаблон иную функцию, лишь бы сигнатура совпадала, и это тоже известно при компиляции.
или я должен инстанциировать шаблон в виде
my_template_type<struct1, set_a_for_struct1, set_b_for_struct1> a;
my_template_type<struct2, set_a_for_struct2, set_b_for_struct2> b;
ну чисто как в си, передаю параметрами указатели (&a, sizeof(int), set_a_for_struct1, set_b_for_struct1);
верно?
А как в С++, расскажи, там сильно иначе?
my_template<struct1> и ожидать у struct1 полей, функций сравнения и прочее
или для int знать, что присваивание и сравнение уже есть и ничего своего дописывать не надо
это позволяет также не допустить
my_template_type<struct1, set_a_for_struct2, set_b_for_struct1> a;
ну и да, передача собственных функций f(T) как параметры шаблона совсем не проблема
my_template<struct1> и ожидать у struct1 полей, функций сравнения и прочее
Разница только в том, что в крестах не перечисляешь функции при инициализации шаблона.
Я считаю, что это мелочи. Впрочем, и в Аде это можно не делать - если параметр не укажешь, компилятор будет сам искать параметр с нужным именем и сигнатурой. Просто иногда надо параметр подменять, например, когда сортируешь по разным признакам.
> это позволяет также не допустить
my_template_type<struct1, set_a_for_struct2, set_b_for_struct1> a;
Компилятор Ады совсем тупой, сигнатуры проверять не умеет?
У крестовиков испокон веков был один фирменный аргумент - автодеструкторы и шаблоны. И сейчас, в споре с Адой, они пытаются применить те же аргументы, не понимая, что тут адапроблем они не найдут, но они всё равно пытаются из головы придумать проблемы, даже не проверяя свои аргументы. Они утверждают, что в Аде шаблоны генерируют переголову для вызова функций по указателю, выдумав это неизвестно откуда, потому что в их мирке только кресты умеют раскрывать шаблоны до конца, генерируя несколько копий функции, они не могут признать, что не только кресты умеют всё это, потому что если признают, то повиснет вопрос - а нахера кресты нужны?
я тебе отвечаю на твой искренний вопрос "ой чем же это ограниченны генерики в моей аде"
а ты всё никак не можешь в это поверить
адопроблемы искать мне не нужно, меня вообще мало интересует язык, на котором в России только ibm ищет одного программиста в столетие, и то по знакомству
Ограничения придумал ты, основываясь на представлениях крестомирка, и ответы твои вымышленные.
ну тогда сишные рантайм-шаблоны еще круче оказываются
мне достаточно объявить, что функция сравнения двух элементов выглядит как f(void const *, void const *), поместить свой генерико-шаблон в длльку и крутая шаблонная функция сортировки работает реально с любым типом, который на момент компиляции генерико-шаблонной функции qsort, безусловно неизвестен
а передача корректных функций при использовании - забота программиста
Компиоятор знает, есть ли функция с таким-то именем и сигнатурой над данным типом, или нет.
> поместить свой генерико-шаблон в длльку
Кстати я не знаю, можно ли Адашаблон поместить в ДЛЛ. Технических препятствий, в отличие от крестов, нету, потому что адашаблон умеен принимать динамическую ипостась.
> а передача корректных функций при использовании - забота программиста
Это плохо. Это должна быть забота языка.
уже же написал в самом начале
> вот такие вот рантайм-шаблоны в аде, всего лишь слабый синтаксический сахар вокруг void *, позволяющий делать минимальные проверки типов и кастинг за программиста
Ну и этот сахар таки очень полезен, так что не надо тут.
но вот незадача, компайл-таймовые шаблоны ады не идут ни в какое сравнение с мощью компайл-таймовых шаблонов С++, они не умеют ничего, кроме как подставить какие то отдельные внешние функции и дай бог заинлайнить их - и имеем тоже code bloat для каждого типа
а реалтаймовые шаблоны столь же ограниченны, как и сишные функции над void *, зато реалтаймовые
срыв покровов бесконечного преимущества метапрограммирования на аде
Да. Они умеют и то, и то, в отличие от крестовых, которые умеют только одно, а если надо и то, и то, то дублируй код.
> какое сравнение с мощью компайл-таймовых шаблонов С++, они не умеют ничего, кроме как подставить какие то отдельные внешние функции и дай бог заинлайнить их
Лол, а что ещё надо? Рассчитать факториал на шаблонах?
Специализация успешно делается через подстановку функции в качестве параметра.
И да, мы можем подставлять разные функции, если хотим сравнивать массив структур по разным признакам.
специализированный шаблон может делать абсолютно другие действия, по сравнению со своим общим собратом, но зачастую его пишут, чтобы на порядок сократить общие действия
С++ умеет охуенные компайл-тайм шаблоны и реалтайм шаблоны через void *
удобно и быстро
ада не умеет охуенные компайл-тайм шаблоны
умеет говношаблоны
и так, мы выяснили, что в говношаблонах ады я могу лишь подставлять другие функции, которые имеют необходимую сигнатуру (а то, что их можно передавать напрямую указателями оппонируют, что как же, оптимизация инлайном - киллирфичя, не иначе). продолжим
в моем типа struct1 объявлен внутренний тип freaking_type
могу ли я создать переменную этого типа в адовском шаблоне?
а вызвать от этой переменной еще методы
предвосхищая твой ответ - видимо да, каждый внутренний тип надо передавать в шапку шаблона, как и каждый метод, который этот тип пользует
могу ли я воспользоваться енумами, объявленными в типе - только через шапку
могу ли я вызвать статический метод - только через шапку
кстати, может ли класс быть шаблонным?
может ли мой класс отнаследоваться от класса, который зависит от шаблона?
например
template <class T>
class Z: public template_base<T>, public template_z_base<Z<T>> {};
код на С++, который в контейнере перебирает все элементы и возвращает нашел ли он элемент V
на аде мне надо передать всю эту рожь в параметры декларации:
is find_exact(std::string, std::string::const_iterator, std::string::value_type,
string_begin_func, string_end_func,
assign_string_iterator_func, compare_string_iterator_func, inc_string_iterator_func, deref_string_iterator_func, char_compare_func);
пока писал, еще вопрос - как в аде с автоматической подстановкой параметров шаблона исходя из переданных аргументов?
Представляете, сколько сейчас баб негодует нетраханными, во время этого спора не на жизнь, а на смерть между представителями двух религий? И так почти каждый день.
подозреваю, что генерики в аде настолько хороши, что ими в реальной жизни никто не пользуются, просто любуются
Подстановки параметров шаблона нет, и анонимных экземпляров шаблонной функции тоже нет, всё должно иметь своё имя.
И, не смотря на это, у Ады всё равно концентрация смысла на кол-во строк кода не меньше, чем в С++, так что твой следующий аргумент про многословность не канает.
И это будут разные шаблоны, дублирующие логику.
> а то, что их можно передавать напрямую указателями оппонируют, что как же, оптимизация инлайном
До тебя не доходит, что один и тот шаблон может быть раскрыт и для конкретных функций, с подстановами, и для неизвестной функции, то есть будут разные копии?
Ололо, то, что vector бывает vector<int> оппонирует тому, что он бывает vector<float>.
> могу ли я воспользоваться енумами, объявленными в типе - только через шапку
package Int_Int_Maps is new Hash_Table(integer, integer);
a: Int_Int_Maps.Table; -- где я что передал через шапку?
> кстати, может ли класс быть шаблонным?
может ли мой класс отнаследоваться от класса, который зависит от шаблона?
Я не понимаю, ты пытаешься шарпопроблемы перенести на Аду? Не выйдет, в Аде именно ШАБЛОНЫ, и на них нет тупых ограничений.
А зачем он нужен там? В С++ и раньше без move конструкторов обходились.
Просто писался шаблон TMove<тип> и писался для него конструктор для тип1.
И любой оператор для тип1 перегружался, не чтобы возвращал тип1, а возвращал TMove<тип1>. Если вернули из выражения TMove<тип1>, то это временный объект и можно перемещать, а если тип1, то это постоянный объект и перемещать нельзя.
Также можно и на Ада скорее всего.
В С++ внутри реализации некоторых стандартных библиотек и boost это использовалось поголовно.
const& запрещает менять значение переданного аргумента. Если тебе это надо - сам делай копию.
Кстати, я так понял, в крестах ссылка - всегда указатель?
КРЕСТООВЕРХЕД
Почти: ссылка всегда указывает на один объект и при передаче аргумента не нужно брать адрес.
да, ссылка это неявный указатель
по адресу переменной ассемблер будет читать и писать её значение в памяти (в т.ч. на стеке)
более того, тебе это не понравится, но все переменные в программе обычно и так располагаются в памяти, и поэтому ассемблеру всё равно придется лезть за значением по адресу
иногда компилятор может понять, что переменная влезает в регистр, и при многократном read-only доступе к ней легко оптимизирует, храня её значение в регистре
Ты сравни - если переменная была на стеке, то обращение к ней - это просто обращение к памяти, находящейся у вершины стека.
А если на стеке - только указатель на неё, то это надо обратиться к памяти на стеке, а потом сделать ещё одно разыменование.
Одним разыменованием больше.
> иногда компилятор может понять, что переменная влезает в регистр, и при многократном read-only доступе к ней легко оптимизирует, храня её значение в регистре
А если не ридонли? Крестокомпилятор умеет передать переменную в функцию в регистре, когда передача идёт по ссылке, то есть, когда важно значение этой переменной (регистра) и при выходе из функции?
я думаю, что это уже нюансы оптимизации, что конкретно для данной группы операций компилятор будет размещать в регистрах, а что оставит с доступом по адресу, на мой личный взгляд даже когда стековой переменной b присваивается значение, небезопасно его придерживать в регистре, потому что может ты хитрожопый хитрован параллельно лезешь в стек грязными пальцами и уже ожидаешь там увидеть новый результат
описанная тобой киллир-фичя ады, когда уверенным в измененных значениях параметров можно быть только при выходе из функции, выглядит как раз оверхедом, когда все все изменения необходимо временно содержать на стеке
встречный вопрос - а до выхода из функции можно быть уверенным в том, что они не точно не изменены?
Ололо, тогда и отпимизация замены виртуального вызова функции на инлайновый в случае, когда тип объекта известен, тоже опасна, потому что меняет логику программы в случае замены указателя на ТВМ.
Твои аргументы работают против крестокомпиляторов уже. Ты не знаешь, как извернуться, чтобы доказать, что крестам эта фича не нужна, вместо того, чтобы признать, что это КРЕСТОПРОБЛЕМА, у тебя крестобаттхёрт короче.
> описанная тобой киллир-фичя ады, когда уверенным в измененных значениях параметров можно быть только при выходе из функции, выглядит как раз оверхедом, когда все все изменения необходимо временно содержать на стеке
Ты сравни - держишь ты на стеке указатель на переменную, или её саму, по памяти один хрен, зато внутри самой функции переголовы нету от постоянных разыменований.
> встречный вопрос - а до выхода из функции можно быть уверенным в том, что они не точно не изменены?
Ты собираешься брать указатель от переменной, которую ты же передал по ссылке? Я не знаю, может для aliased переменных и иначе работает. А для не-aliased указатель брать нельзя (все переменные, от которых тебе нужен указатель, ты должен руками пометить как aliased, тем самым ты не можешь случайно наворотить указателеговно ).
я просто хотел уточнить верно ли то, что изменение переменной переданной по ссылке в адовскую функцию, изменит реальную память этой переменной только при выходе из функции
или в этом нельзя быть уверенным?
т.е. есть ли реальная атомарность или это просто лишний батхёрт?
Да, это верно для типов, помещающихся в регистр, и у которых нету aliased. Дальше - не знаю. Нефиг логику строить на этих нюансах.
все претензии к тому, что компилятор ады без принуждения делает оптимизацию -fipa-sta, а в компиляторе С++ это надо задавать при компиляции
при этом С++ позволяет руками заявить четкий доступ к переменным - где ссылки а где значения на стек, а в аде такой возможности уже нет
зато не надо писать &, но надо писать рrocedure
опасна, конечно
ты еще не привык, что программист на С++ всегда может выстрелить в свою ногу?
это тебе не комната с мягкими желтыми стенами
Идея интересная. Я так понимаю - каждая функция Ада работает как бы в песочнице и не имеет воздействия на среду исполнения, если произошло исключение?
Песочницы нет, просто такая оптимизация для передачи по ссылке.