Здравствуйте, Максим Рогожин, Вы писали:
МР>Это понятно. Но я думал, что void как раз и означает что функция не возвращает СОВСЕМ НИКАКОГО значения. Это не так?
Нет, не так. void — это специальный тип-пустышка, тип-джокер.
void foo(void *p)
{
int x = (int)p; // трактуем указатель p как обычное целое число
int y = *(int*)p; // трактуем указатель p как указатель на целое число и сразу разыменовываем
int z = ******************************************************(int******************************************************)p; // это компилируется, я проверял
void *wut = (void*)( p ? (int)p ^ (int)p : (int)p % (int)p); // ну, мне пора :)
}
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, Максим Рогожин, Вы писали:
МР>>Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)?
Pzz>Нет, просто договоренность такая, что конструктор не имеет явно указанного возвращаемого типа. Конструктор в любом случае — особая функция, и компилятор понимает, как для него организовывать стек и прочий пролог.
А меня всегда удивляло почему нельзя было для конструктора и деструктора зарезервировать какие-нибудь имена, а не писать имя класса каждый раз.
И почему private выбрали по умолчанию вместо public. Не говоря уже об отсутствие аккумулятора и возрате последнего значения как в perl
Типа такого
// header
class A : B {
ctor();
dtor();
nonvirtual void fn();
void gn()=0;
};
// impl
implement class A {
ctor() { ... }
dtor() { ... }
void fn() { parent::member(); }
}
А указатели на методы класса всегда вызывали смутные эмоции.
Здравствуйте, kov_serg, Вы писали:
_>А меня всегда удивляло почему нельзя было для конструктора и деструктора зарезервировать какие-нибудь имена, а не писать имя класса каждый раз.
Ну например за тем, чтобы не вводить еще одного ключевого словак, которое, тем самым, станет недоступным в качестве идентификатора.
_>И почему private выбрали по умолчанию вместо public.
Это как-раз правильно. Если бы все члены классов были по умолчанию public, то у индусов в программах вообще все члены были бы всегда public, и никакого ограничения видимости никто бы не использовал.
_>Не говоря уже об отсутствие аккумулятора и возрате последнего значения как в perl
Это я не слишком-то понял.
_>А указатели на методы класса всегда вызывали смутные эмоции.
А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...
Здравствуйте, Pzz, Вы писали:
_>>Не говоря уже об отсутствие аккумулятора и возрате последнего значения как в perl Pzz>Это я не слишком-то понял.
int min(int x,int y) { if (x<y) x; else y; }
int x={ if (a<0) 0; else a; };
min(z[0],z[1]); min(_,z[2]); min(_,z[3]);
int last_result=_;
_>>А указатели на методы класса всегда вызывали смутные эмоции. Pzz>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...
да стрелку могли бы приспособить для правого присвоения
10+2*5 -> a
У gcc есть такое расширение. Но в принципе, эта конструкция — источник глупых ошибок. Откуда компилятору знать, я действительно имел ввиду последнее значение в блоке, или просто забыл сказать return где-то в середине?
Pzz>>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая... _>да стрелку могли бы приспособить для правого присвоения _>10+2*5 -> a
Угу. А еще надо присваивание вверх и вниз:
int a, b;
^
b = 10 + (2*5)|;
Промежуточное значение заносим в переменную a, а окончательный результат — в переменную b.
Здравствуйте, rg45, Вы писали:
R>Эти две записи похожи лишь формально. Только в первом случае это является не возвращением значения, а прямым конструированием объекта в правой части инициализатора. Это то же самое выражение, которое используется в операторе return в функции createObject:
То-то это добавляет радости разработчикам компилятора, которым теперь в любом месте, которые выглядит, как вызов функции, надо разрезолвить имя и разобраться, функция ли это на самом деле, или конструирование объекта.
А чтобы жизнь им окончательно не казалось медом, пространство имен функций и пространство имен типов — это разные пространства. Т.е., в принципе, имя функции может совпадать с именем класса, и поэтому надо сначала пытаться найти имя среди имен функций, а потом — среди имен типов.
Pzz>У gcc есть такое расширение. Но в принципе, эта конструкция — источник глупых ошибок. Pzz>Откуда компилятору знать, я действительно имел ввиду последнее значение в блоке, или просто забыл сказать return где-то в середине?
return это выход из функции. А тут последнее значение можно передавать в функцию по умолчанию
(неявно как this) при этом жесткая типизация и шаблоны позволили бы сделать очень интересные вещи.
Pzz>>>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Pzz>>>Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая... _>>да стрелку могли бы приспособить для правого присвоения _>>10+2*5 -> a
Pzz>Угу. А еще надо присваивание вверх и вниз:
Pzz>
Pzz>int a, b;
Pzz> ^
Pzz>b = 10 + (2*5)|;
Pzz>
Pzz>Промежуточное значение заносим в переменную a, а окончательный результат — в переменную b.
Вы чертов гений! Надо вообще сделать 10+2*5->(goto +10,-2) или 10+2*5->(looks like z[] or has prefix result_) или 0->(all unsigned)
Вообще rightward operator иногда очень даже удобен https://stat.ethz.ch/R-manual/R-devel/library/base/html/assignOps.html
ps: Напомню: "что настоящий ученый может писать фортраном на любом языке"
Здравствуйте, Pzz, Вы писали:
_>>А меня всегда удивляло почему нельзя было для конструктора и деструктора зарезервировать какие-нибудь имена, а не писать имя класса каждый раз. Pzz>Ну например за тем, чтобы не вводить еще одного ключевого словак, которое, тем самым, станет недоступным в качестве идентификатора.
А это уже недоработка другая, но тоже в языке. Вон в дотнете в каждом языке обязаны как-то разрешить использовать любое ключевое слово в качестве идентификатора.
Представим себе язык, где $ — префикс "это всегда идентификатор", а @ — "это всегда ключевое слово"; без префикса — есть список стандартно понимаемых ключевых слов (и в некоторых контекстах может расширяться). Допустить даже варианты типа $"a b c", если кому-то нужны такие дикие идентификаторы.
Тогда можем получать и любые идентификаторы, и возможность пробных расширений языка на новые использования. Захотел какое-нибудь @foomode — добавил без конфликта; устоялось — объявил, что через 3 года будет пониматься без '@' — у всех есть время переключиться.
На самом деле тот же C# частично начал двигаться в эту сторону за счёт рекомендации стиля использовать заглавные для любого внешнего идентификатора — зона конфликта резко сокращается и, что главное, обычно не выходит за пределы внутренностей модуля. Go это формализовал до конца — там заглавная обязательна для экспорта, ключевые слова только со строчной, и они не опасаются за устойчивость любых пользовательских API против этого расширения.
А писать init вместо CVeryLongAndTerribleApiBeastFactory, по-моему, достаточно удобно
_>>И почему private выбрали по умолчанию вместо public.
Pzz>Это как-раз правильно. Если бы все члены классов были по умолчанию public, то у индусов в программах вообще все члены были бы всегда public, и никакого ограничения видимости никто бы не использовал.
Pzz>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...
Почему Go, меня и после Python и Java это удивляет хорошо хоть ошибки обычно тривиальные.
Pzz>У gcc есть такое расширение. Но в принципе, эта конструкция — источник глупых ошибок. Откуда компилятору знать, я действительно имел ввиду последнее значение в блоке, или просто забыл сказать return где-то в середине?
А это надо решать точно так же, как с проблемой if (a = b): требовать явной пометки таких случаев. Вводим новое слово — например, take.
if (a == b) — нет проблем. if (take a = b) — нет проблем, при чтении чётко понятно, что тут ещё и присвоение. if (a = b) — не компилируется, присвоение без take не имеет понятия результата. a = take b = take c = 0 — побочный эффект, чуть больше слов. Но такие конструкции сейчас очень редки, так что можно потерпеть. a = take if (x > 0) x; else -x; — явно берём результат ifʼа, компилятор знает, что блоки внутри if должны выдавать значение.
Pzz>Угу. А еще надо присваивание вверх и вниз:
Здравствуйте, netch80, Вы писали: N>Здравствуйте, Максим Рогожин, Вы писали: МР>>Почему нельзя писать так МР>>class A { МР>>public: МР>> void A() {} МР>>}; МР>>? N>Страуструп писал, что это для подчёркивания того факта, что конструктор никогда не зовётся напрямую.
МР>>Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)? N>Вот принятое в Unix ABI, например, знает
N>В этом случае тот конструктор, что с C3, аллоцирует память и возвращает адрес объекта, а те, что C1 и C2, получают первым скрытым параметром адрес объекта и ничего не возвращают. N>Больше отличий нет, остальное идентично обычной функции. N>Для MSVC правил не знаю, могут быть хитрости.
так а, действительно, что тогда мешает официально изменить семантику конструктора на вариант наподобие "создает объект класса и инициализирует его, после чего возращает ссылку на этот объект"?
(токо недавно обсуждали, что, например, в таком случае такое новое понятие, как User-defined deduction guides, можно было бы тогда свести к декларации шаблона такого конструктора. это я к тому, что, возможно, это могло бы помочь с введением новых нужных понятий через уже старые.)