в духе
using Foo = int;
using Bar = int;
Foo foo = 0;
Bar bar = foo; // Error: could not cast Foo to const Bar& in Bar::Bar(const Bar&)
?
Нет, это решается библиотеками
Я боюсь это никогда не появится, ибо сломает тонны кода.
Не обязательно же такой синтаксис как я предложил. Можно что-то вроде strong using Foo = int; или что-нибудь со старыми ключевыми словами, чтоб не совсем не ломать: using class Foo = int; // По аналогии с "сильным" enum class.
Были предложения, обычно такое называется strong typedef. И все предложения рушатся вопросами: 0. Должна ли конвертация из int в Foo или Bar быть явной или неявной? А наоборот? А между ними? 1. Должен ли operator== работать "из коробки" для таких типов (в том числе комбинации int==Foo, Foo==Bar)? 2. Должен ли std::hash работать также, как для оригинального типа? 3. Должны ли поддерживаться арифметические операции для Foo, у которого "базовый" тип их поддерживает? 4. Если ответы на все вопросы выше - нет, то почему нельзя взять struct Foo { int value; }? P.S. Вообще, ответы на все эти вопросы у каждого свои, а универсального решения придумать не смогли
Спасибо. Мне кажется, на вопросы 1 и 3 ответ должен быть "да", иначе используйте обычный using/typedef. А есть ли где нибудь лог обсуждения со всем списком подобных вопросов? Чтобы будущие предложения на них заранее ответили.
0 - все конвертации максимально явные, почти как в Аде.
0. Явная. 1. Да. Сравнения допустимы. Но через тег опцианальны. 2. Нет, это разные типы. С разными констрейнтами. 3. Да. Итого - Ada Language, SubType Idiom.
Осталось только контракты навешать.
0. Почему? 1. Почему? 2. Почему? 3. Точно? А если у меня using strong user_id = int, что такое user_id{1} + user_id{2}? Или user_id{5} * user_id{7}? Все эти вопросы скорее риторические, на них не нужно отвечать (всё, что пришло мне в голову сходу, на самом деле можно приплести много чего ещё - операторы сравнения, поведение при наследовании, правила алиасинга, всякие там friend'ы и т.д...). Просто для каждой задачи, как выяснилось, нужно что-то своё. Есть классный пост на эту тему - https://foonathan.net/2016/10/strong-typedefs/ Конкретных свежих пропозалов в стандарт я не нашёл, увы.
0. Разве не ради этого всё и задумывалось? Чтоб нельзя было положить FirstName в SecondName? 1. Типы разные, неявное сравнение недопустимо, ты прав. Иначе отстрел ног на ровном месте. 2,3 - ХЗ, от ситуации зависти, я б напилил концептов с разынми policy.
enum class Foo : int {}; enum class Bar : int {};
Для строк часто используется, их в енам не сунешь
Наследоваться можно запретить, как у примитивных типов. Алиасинг тоже как у примитивных. Почему это всё должно отличаться от примитивных типов? Конструирование/присваивание/мув максимально явны. Арифметику и сравнения можно запретить по дефолту, но сделать лёгкий синтаксис для их быстрого включения, вроде operator+(Foo, Bar); // Теперь ниже объявления (или во всей единице трансляции?) эти типы можно складывать.
Скорее explicit using
Так уже сейчас есть, только вместо using надо enum class
И как это будет работать, можно пример? Разве после enum class Foo : int {}; enum class Bar : int {};
Обсуждают сегодня