Изменение видимости перечисления при "opaque enum declaration"

develoit
develoit
class foo
{
    enum class some_enumerable_type : std::size_t;
    some_enumerable_type value_;

public:

    enum class some_enumerable_type : std::size_t
    {
        identifier0,
        identifier1,
        identifier2,
//        ...
        identifierN
    };

    foo() noexcept : value_{some_enumerable_type::identifier0} {}
    foo(some_enumerable_type value) noexcept : value_{value} {}
};

int main()
{
    auto value = foo::some_enumerable_type::identifier1;
    std::cout << static_cast<std::size_t>(value) << std::endl;
}


Данный пример не сработает. Конечно, можно перенести объявление переменной после определения перечисления, но! тогда какой смысл в возможности предекларации перечеслений (особенно с явным указанием базового типа)?
Может имеет смысл исправить такое поведение?

Да, и еще) может и static_cast для enum`ов ликвидировать в случаях когда требуемый тип совпадает с базовым?

enum class color : std::size_t { red, green, blue };

std::size_t c1 = static_cast<std::size_t>(color::green); //ok
std::size_t c2 = color::red; //error

//или

std::size_t blend(std::size_t c1, std::size_t c2, ...) { ... }

auto bc1 = blend(
    static_cast<std::size_t>(color::red),
    static_cast<std::size_t>(color::green)); //ok
auto bc2 = blend(color::red, color::blue); //error

-4
рейтинг
11 комментариев
mirgorodskiysk
Полностью согласен с предложением! Если у тебя в функции будет, к примеру, 10 параметров - везде нужно писать static_cast-ы - это АД!
mirgorodskiysk
Antervis
mirgorodskiysk, strong typed enum для того и нужен, чтобы быть отдельным типом перечисления, в отличие от обычного enum-а.
Antervis
develoit
Antervis, это не основное предложение) всего лишь синтаксическое "послабление" когда требуемый тип совпадает с базовым, не более. прокомментируй основное предложение, пожалуйста;)
develoit
develoit
Прокомментируйте почему "нет", пожалуйста (хотя бы за основное предложение).
develoit
yndx-antoshkka
develoit, расскажите подробнее, как вы хотите чтобы поведение было исправлено? Чего вы ожидаете? Чего вы хотели добиться изначально?
yndx-antoshkka
develoit
yndx-antoshkka, сейчас если scoped-перечесление (с указанием базового типа или без) предварительно объявить в private-секции класса, то не важно в какой секции оно будет определено - оно останется private. Хотелось бы, чтобы область видимости перечисления задавалась секцией его определения, а не объявления (тем более для перечислений с указанием базового типа). Это касаемо основного предложения.

Еще, для scoped-перечислений с указанием базового типа (только так!) хотелось бы не писать static_cast тогда, когда базовый тип перечисления совпадает с типом, к которому требуется преобразование. Если "на пальцах", то, чтобы вариант 2 в примере ниже не заставлял компиляторы ругаться, тогда как вариант 3 продолжал требовать привлечения static_cast.

enum class color : std::size_t { red, green, blue };
long c1 = static_cast<long>(color::red); //1
std::size_t c2 = color::green; //2
int c3 = color::blue; //3
develoit
yndx-antoshkka
develoit, первая часть вашего предложения поломает существующий код и из-за этого её никто не примет.

Вторая часть вашего предложения (именно в таком виде) ухудшит type safety програм и соотвественно тоже не пройдет в комитете. Можно постараться как-то переформулировать её и слегка поменять поведение, но не понятно как именно.
yndx-antoshkka
develoit
yndx-antoshkka, вот не понимаю как оно может поломать существующий код? можете пример привести, пожалуйста, как было и работало, и как перестанет работать если принять предложение?
опять же, чем именно ухудшит type safety вторая часть, если только преобразование из перечисления в некоторый тип предполагается при полном совпадении последнего с базовым типом перечисления?

как по мне, так ничего не должно поломаться. возможно я дико ошибаюсь)
develoit
yndx-antoshkka
develoit, поломает например вот тут:

struct foo {
enum class some_enumerable_type : std::size_t;
some_enumerable_type value_;

private:
enum class some_enumerable_type : std::size_t
{
identifier0,
identifier1,
identifier2,
// ...
identifierN
};
}

class enum X - отдельный тип данных X. Вы предлагаете добавить оператор неявного преобразования ко всем enum. Это ведёт к ошибкам, для решения которых были добавляены explicit операторы в C++11.
yndx-antoshkka
develoit
yndx-antoshkka, согласен, Ваш пример сломается, но он мало показателен и больше смахивает на ошибку что ли) согласитесь, объявлять тип в секции public, а затем определять его в private нелепо, сомнительно с прикладной точки зрения; сейчас оно сработает, но выглядит как-то запутанно, не однозначно. мой вариант строг в этом моменте - в какой секции определили enum, так он и виден во вне. предварительное объявление ведь совсем не для задания видимости в данном случае, а для возможности разместить переменную, зная базовый тип перечисления. именно определение перечисления в той или иной секции должно выражать намерение программиста, вносить ясность о видимости определяемого типа-перечисления, но никак не предекларация.

я понимаю, что class enum X - это отдельный тип и отнюдь не предлагаю добавлять оператор неявного преобразования ко всем enum. я вполне понимаю для защиты от каких ошибок добавляли explicit операторы, но вторая часть моего предложения не из этой оперы. писать
std::size_t c = color::red;
вместо
std::size_t c = static_cast<std::size_t>(color::red);
при color = enum class : std::size_t { red, ...};
это сродни пропуску списка параметров в определении лямбды, когда их попросту нет. не более.

Но! на нет и суда нет) Вам виднее)
develoit
yndx-antoshkka
develoit, хм... если так сильно ограничивать (делать фактически explicit операторы приведения) то идея интересная. Но нужно очень много исследований и проработать сразу большую часть проблем с enum:
* операторы для enum из коробки?
* расширить список типов для enum?
* enum которые всегда хранят только одно из значений enum
* ...

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

Это адовая исследовательская работа. Если хотите заняться - помогу чем смогу.
yndx-antoshkka
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).