Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.04.20 03:52
Оценка:
Когда еще в середине 2000-х смотрел Microsoft Extensions в VC++, обратил внимание на compiler-supported type traits, но почему-то посчитал, что они поддерживаются только в CLR — ну и забыл о них. На днях обнаружил, что почти все поддерживаются и в native, и обрадовался было, но сразу же сообразил, что в VC++ нет адекватного способа их использовать. Импотентские __if_exists/__if_not_exists, придуманные чьим-то межушным ганглием, имеют крайне ограниченное применение.

И вот интересно стало: в документации примеры использования этих traits приведены исключительно в run-time. А какой в этом может быть практический смысл? Что дельного можно построить на этих конструкциях, используя результаты проверок только во время выполнения? Или это такой предельно уродливый способ диагностики потенциальных проблем, доступный только в run-time?

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

В общем, с какой практической целью можно было выродить такое, упорно избегая вводить в язык что-то вроде __if для проверки во время компиляции любого константного выражения?
vc++ microsoft compiler type traits __is_pod __is_enum __is_base_of __has_assign
Re: Compiler-supported type traits в MS VC++
От: okman Беларусь https://searchinform.ru/
Дата: 13.04.20 07:35
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>И вот интересно стало: в документации примеры использования этих traits приведены исключительно в run-time. А какой в этом может быть практический смысл? Что дельного можно построить на этих конструкциях, используя результаты проверок только во время выполнения?


Эти конструкции вычисляются в compile time. Например, можно так делать:
template <class T, class = std::enable_if<__has_virtual_destructor(T)>::type>
struct Test
{
};

Test<A> test; // Не скомпилируется, если у A нет виртуального деструктора.
Re[2]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.04.20 08:03
Оценка:
Здравствуйте, okman, Вы писали:

O>Эти конструкции вычисляются в compile time.


Дык, и я о том же.

O>Например, можно так делать:


Так и об этом я тоже упомянул: MS, добавив в компилятор эти предикаты, не догадались (и спустя пятнадцать лет не могут догадаться) добавить простейшую конструкцию вроде __if_exists, но принимающую логическое выражение. То есть, эти предикаты, реализованные в компиляторе, практически невозможно использовать без вложенных шаблонных конструкций, которые они (предикаты), по идее, и призваны были заменить.

Вот я и пытаюсь найти в таком подходе логику. Вы ее видите?
Re[3]: Compiler-supported type traits в MS VC++
От: Alexander G Украина  
Дата: 13.04.20 09:51
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Вот я и пытаюсь найти в таком подходе логику. Вы ее видите?


Шаблонные конструкции сильно упрощаются, фактически, не нужно реализовывать __if_exists, шаблон реализует.

Кроме того, шаблонный параметр — не единственное использование compile-time значения.
Ещё есть if constexpr. И размер массива например. И всё это можно считать в constexpr функциях.

Даже шаблон может быть достаточно удобен, если совместить с каким-то std::conditional_t.

Следует отметить, что всё вышеназванное, кроме, собственно, __if_exists — стандартный С++.
Так что это скорее проблема С++, что использовать компайл-тайм константы для изменения структуры программы не так удобно.
Они своим расширением, скорее, предоставили именно реализацию, чем удобство.

Что до возможности сделать без __if_exists. Ну можно, но шаблонной магии нужно больше.
Есть же ещё забота о throughput компиляции, чтобы во время компиляции не тратить время на ненужные действия.
Использование таких магические компайл-тайм функций решает эту проблему, особенно, если стандартная библиотека реализовываен свои <type_traits> через них.
Русский военный корабль идёт ко дну!
Re[4]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.04.20 10:06
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Шаблонные конструкции сильно упрощаются, фактически, не нужно реализовывать __if_exists, шаблон реализует.


А если бы вместо __if_exists сразу было реализовано что-то вроде __if, куда можно было бы подставить и __exists (), то и многое другое сильно упростилось бы. А уровень сложности реализации остался бы тем же.

AG>Ещё есть if constexpr.


Да, аккурат через 13 лет после __if_exists они смогли и if constexpr, когда это утвердили в стандарте.

AG>Даже шаблон может быть достаточно удобен, если совместить с каким-то std::conditional_t.


Подобные шаблоны могут быть достаточно удобны только при отсутствии адекватных альтернатив. Они ж, по сути, делались от безысходности.

AG>Следует отметить, что всё вышеназванное, кроме, собственно, __if_exists — стандартный С++.

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

Разумеется, отсутствие условных конструкций времени компиляции, кроме убогого препроцессора — старая проблема C++, которая лишь недавно стала со скрипом решаться.

AG>Они своим расширением, скорее, предоставили именно реализацию, чем удобство.


Вот я и пытаюсь понять, почему они реализовали очень ограниченную функциональность, когда ровно при тех же затратах можно было реализовать куда более широкую?
Re[5]: Compiler-supported type traits в MS VC++
От: flаt  
Дата: 13.04.20 10:39
Оценка: 16 (1)
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>А если бы вместо __if_exists сразу было реализовано что-то вроде __if, куда можно было бы подставить и __exists (), то и многое другое сильно упростилось бы. А уровень сложности реализации остался бы тем же.


Так и есть:

Do not use __if_exists under any circumstances whatsoever.


The sad history of Visual Studio’s custom __if_exists keyword
Отредактировано 14.04.2020 9:30 flаt . Предыдущая версия .
Re[6]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.04.20 10:57
Оценка:
Здравствуйте, flаt, Вы писали:

ЕМ>>А если бы вместо __if_exists сразу было реализовано что-то вроде __if, куда можно было бы подставить и __exists (), то и многое другое сильно упростилось бы. А уровень сложности реализации остался бы тем же.


F>Так и есть:


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

F>[url=https://devblogs.microsoft.com/oldnewthing/20190828-00/?p=102812]The sad history of Visual Studio’s custom __if_exists keyword[/q]


Я видел эту заметку. Чен вообще толковый мужик, но предлагать делать подобное на нечеловеческой логике шаблонов — это явное извращение.
Re[3]: Compiler-supported type traits в MS VC++
От: okman Беларусь https://searchinform.ru/
Дата: 13.04.20 13:43
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Вот я и пытаюсь найти в таком подходе логику. Вы ее видите?


Я вообще вижу не сильно много логики в тех фичах, которые MS последние годы пихает в Windows, Visual Studio и компиляторы...
Re[4]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.04.20 14:09
Оценка:
Здравствуйте, okman, Вы писали:

O>Я вообще вижу не сильно много логики в тех фичах, которые MS последние годы пихает в Windows, Visual Studio и компиляторы...

O>

Ну, предикаты __is_* и __has_* они запихали около пятнадцати лет назад, а __if_exists — аж двадцать пять, где-то в районе VS 6... Впрочем, в те времена про MS говорили то же самое.
Re: Compiler-supported type traits в MS VC++
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.04.20 10:58
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>И вот интересно стало: в документации примеры использования этих traits приведены исключительно в run-time. А какой в этом может быть практический смысл? Что дельного можно построить на этих конструкциях, используя результаты проверок только во время выполнения?
А разве в compile-time они не работают?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 14.04.20 11:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А разве в compile-time они не работают?


Я ж вроде достаточно ясно описал, что предикаты, как раз, работают исключительно в compile-time, а примеры их использования от MS работают, опять же исключительно, в run-time. То есть, непонятно, как эти средства компилятора можно использовать другими средствами того же компилятора. Пока единственное, что приходит в голову — это частично-специализированные шаблоны, но их к тому времени уже наделали и для проверки условий, для которых добавлены предикаты. То есть, я просто не вижу в этом логики.
Re[3]: Compiler-supported type traits в MS VC++
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.04.20 12:32
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Я ж вроде достаточно ясно описал, что предикаты, как раз, работают исключительно в compile-time, а примеры их использования от MS работают, опять же исключительно, в run-time. То есть, непонятно, как эти средства компилятора можно использовать другими средствами того же компилятора. Пока единственное, что приходит в голову — это частично-специализированные шаблоны, но их к тому времени уже наделали и для проверки условий, для которых добавлены предикаты. То есть, я просто не вижу в этом логики.

Эмм, ну, как бы традиционно должны работать if constexpr и да, параметризация шаблонов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 14.04.20 12:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Эмм, ну, как бы традиционно должны работать if constexpr


Эти предикаты были введены за много лет до того, как if constexpr вообще появился, не говоря уже о традиционности.

S>и да, параметризация шаблонов.


Что "да"?
Re[5]: Compiler-supported type traits в MS VC++
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.04.20 05:54
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Эти предикаты были введены за много лет до того, как if constexpr вообще появился, не говоря уже о традиционности.

__has_copy()? Я думал, это недавние нововведения.
ЕМ>Что "да"?
Да, вы можете использовать результаты этих предикатов в параметрах шаблонов, определяя поведение своих типов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.04.20 06:34
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>__has_copy()? Я думал, это недавние нововведения.


В VC++ 14.00 (VS 2005, Win 5.2 SDK).

S>Да, вы можете использовать результаты этих предикатов в параметрах шаблонов, определяя поведение своих типов.


А смысл? На тот момент уже было наделано реализаций тех же предикатов на шаблонах.

Вот если б они изначально додумались вместо убогого __if_exists сделать универсальный __if, то даже с единственным предикатом вроде __exists () получилась бы неимоверно мощная фича, причем при ровно тех же затратах. И в ней можно было бы использовать свои шаблонные конструкции, и ее можно было бы вставлять внутрь любого шаблона. Это же очевидно любому, кто хоть мало-мальски поработал с изменяемыми типами. Как они могли так протупить — не представляю. Ведь в первую очередь для себя делали, а уже потом для остальных.
Re[7]: Compiler-supported type traits в MS VC++
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.04.20 08:44
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>А смысл? На тот момент уже было наделано реализаций тех же предикатов на шаблонах.

Вот хз. Наверное, хотели ускорить компиляцию — SFINAE довольно дорогая штука. Вообще, я попробовал найти на просторах интернета реальный код с этими предикатами — не смог. Нашёл какие-то тесты компилятора на гитхабе, и это всё.
Может, они каким-то стандартом навязаны?

ЕМ>Вот если б они изначально додумались вместо убогого __if_exists сделать универсальный __if, то даже с единственным предикатом вроде __exists () получилась бы неимоверно мощная фича, причем при ровно тех же затратах. И в ней можно было бы использовать свои шаблонные конструкции, и ее можно было бы вставлять внутрь любого шаблона. Это же очевидно любому, кто хоть мало-мальски поработал с изменяемыми типами. Как они могли так протупить — не представляю. Ведь в первую очередь для себя делали, а уже потом для остальных.

Ну, вокруг конкретно этой фичи история известная: запилили конкретный костыль для конкретного сценария; и запихали в дальний угол, т.к. развивать дальше мотивации не было.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.04.20 12:36
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну, вокруг конкретно этой фичи история известная: запилили конкретный костыль для конкретного сценария; и запихали в дальний угол, т.к. развивать дальше мотивации не было.


Ладно, если б просто не было мотивации развивать дальше. Но они ж, по сути, реализовали if constexpr на пятнадцать лет раньше его включения в стандарт. Если бы они не склеили насильно две совершенно независимых сущности (условную трансляцию на уровне компилятора и предикат существования определения), то получилась бы чертовски мощная и полезная фича. А то убожество, что они выродили, только и оставалось запихать в дальний угол, а потом стыдиться.
Re[9]: Compiler-supported type traits в MS VC++
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.04.20 13:10
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Ладно, если б просто не было мотивации развивать дальше. Но они ж, по сути, реализовали if constexpr на пятнадцать лет раньше его включения в стандарт. Если бы они не склеили насильно две совершенно независимых сущности (условную трансляцию на уровне компилятора и предикат существования определения), то получилась бы чертовски мощная и полезная фича. А то убожество, что они выродили, только и оставалось запихать в дальний угол, а потом стыдиться.
Я думаю, что там была настолько кривая реализация, что расклеить независимые сущности было в десять раз дороже. Это же вполне обычное дело — когда пилишь специфическую вещь, можно срезать много углов.
А когда делаешь честную универсальную — там вылазит такое количество разнообразных corner cases, что их тестами-то обложить вспотеешь, не то что правильно реализовать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Compiler-supported type traits в MS VC++
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.04.20 16:31
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Я думаю, что там была настолько кривая реализация, что расклеить независимые сущности было в десять раз дороже. Это же вполне обычное дело — когда пилишь специфическую вещь, можно срезать много углов.


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

__if_exists/__if_not_exists имеют стандартный синтаксис — условие в круглых скобках и компилируемый/пропускаемый текст в фигурных. Из круглых скобок анализатор должен выбрать, как минимум, идентификатор типа, объекта или функции, а по факту — конструкцию почти произвольной сложности (например, он понимает "Selector <FirstCond + 5, __is_enum (Enum)>"). Затем он должен найти в своих таблицах определение, и либо обработать, либо пропустить текст внутри фигурных скобок.

Какие Вы видите гипотетические сложности против того, чтобы из круглых скобок выбирать константное арифметическое выражение, а означенную конструкцию — из предиката вроде __exists () или __not_exists ()?
Re[11]: Compiler-supported type traits в MS VC++
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.04.20 12:12
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Есть предположения, какие именно углы можно было срезать? Только не "с точки зрения банальной эрудиции", а практически. Я таких не вижу.

Практически сразу видим разное количество тест кейзов. Как только мы сделали общий оператор условной компиляции, то надо проверять его на сотне разных видов constexpr.
На практике там скорее всего было заведено два-три теста по мотивам фиче реквеста от команды ATL.
То, что он понимает конструкции произвольной сложности — скорее всего непреднамеренный эффект. Который, кстати, может быть а) нестабильным (т.е. неожиданно валиться на одних параметрах, и работать с другими), и б) неконсистентным — то есть плавать от версии к версии.

ЕМ>__if_exists/__if_not_exists имеют стандартный синтаксис — условие в круглых скобках и компилируемый/пропускаемый текст в фигурных. Из круглых скобок анализатор должен выбрать, как минимум, идентификатор типа, объекта или функции, а по факту — конструкцию почти произвольной сложности (например, он понимает "Selector <FirstCond + 5, __is_enum (Enum)>").

Понимает? Это случайность. По документации — не обязан.
ЕМ>Затем он должен найти в своих таблицах определение, и либо обработать, либо пропустить текст внутри фигурных скобок.
Хмм. А этот текст внутри скобок может ли представлять собой неполный синтаксис? Ну, там, хотим в зависимости от чего-то добавить перед мембером модификатор static?
ЕМ>Какие Вы видите гипотетические сложности против того, чтобы из круглых скобок выбирать константное арифметическое выражение, а означенную конструкцию — из предиката вроде __exists () или __not_exists ()?
К моменту выхода __if_exists понятие константного арифметического выражения уже было? Или нужно было его изобрести, ввести в компилятор его поддержку, и только потом уже пилить __if()?
Даже если да, основная сложность в построении компилятора — тестирование. Эта штука должна корректно обрабатывать корректные конструкции, и корректно падать при некорректных.
Недостаточно просто объявить "а вот тут мы берём и кладём произвольное константное выражение, приводимое к bool". Нужно завести пачку тестов, которые содержат интересные нам константные выражения, как корректные, так и некорректные, и убедиться, что компилятор всё это корректно прожёвывает.
Можно ли сделать так, чтобы результат вычисляемого выражения зависел от включения условного кода? Т.е.
struct M
{
   static const bool a = __if(M::a) {false } __if(!M::a) { true}
}

Как должен компилятор обрабатывать такой код?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.