implicit operator bool
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 15.03.24 21:42
Оценка:
Здравствуйте!

Есть флаговый enum, для него определены все бинарные операции, возвращают тот же enum.

Я пока не делал operator bool, мало ли что вылезет. Но, в условных операторах уже устал писать ==0 / !=0.

Ну вот и подмывает уже эту мелочь переделать. Тут ещё анноит то, что с интегральными типами можно просто написать if (condition), а с enum'ом надо писать if (condition!=0)

На какие грабли можно нарваться?

Какие про/контра будут?
Маньяк Робокряк колесит по городу
Re: implicit operator bool
От: rg45 СССР  
Дата: 16.03.24 01:01
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Есть флаговый enum, для него определены все бинарные операции, возвращают тот же enum.


M>Я пока не делал operator bool, мало ли что вылезет.


А как ты собираешься сделать оператор bool для перечисления? Его ведь можно сделать только как функцию-член.

M>Но, в условных операторах уже устал писать ==0 / !=0.


Если условный оператор понимает конструкции if(x==0) и if(!=0), значит enum обычный, unscoped, а значит, услоный оператор так же точно способен понять и конструкции if(x) и if(!x) и никаких операторов для этого определять не нужно.

M>На какие грабли можно нарваться?


Да грабли могут быть самые разноообразные. Вот из недавнего, например. Был у нас чудо-юдо-супер-говно класс, написанный хрен знает когда для якобы эффективной работы со всякими строками. Объекты этого класса часто использовались в качестве ключей ассоциативных контейнеров. Для этих целей в этом классе был определены операторы сравнения (обычные). И вот, настало время переходить на C++20. Ну, попыхтели-попыхтели и перешли. И, как потом выяснилось, все ассоциативные контейнеры в новой реализации стандартной библиотеке используют уже новый spaceship оператор <=>. Такого оператора в этом классе, конечно же, не было. Зато в этом классе были определены операторы неявного преобразования к char* и const char*, для которых (внезапно) оператор <=> определен. Ну вот эти операторы преобразования и подхватились. И пошло сравнение голых указателей, вместо сравнения содержимого строк. И ведь все успешно откомпилировалось, а ошибку ловили уже в рантайме. А, как известно, чем дурнее ошибка, тем дольше ты ее будешь ловить. И это лишь единичный пример, а вообще, это очень западлистая штука, эти неявные преобразования. И никакой фантазии не хватит, чтоб представить, во что это счастье может вылиться.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 16.03.2024 1:03 rg45 . Предыдущая версия .
Re[2]: implicit operator bool
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 16.03.24 01:10
Оценка:
Здравствуйте, rg45, Вы писали:

M>>Я пока не делал operator bool, мало ли что вылезет.


R>А как ты собираешься сделать оператор bool для перечисления? Его ведь можно сделать только как функцию-член.


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


M>>Но, в условных операторах уже устал писать ==0 / !=0.


R>Если условный оператор понимает конструкции if(x==0) и if(!=0), значит enum обычный, unscoped, а значит, услоный оператор так же точно способен понять и конструкции if(x) и if(!x) и никаких операторов для этого определять не нужно.


enum — scoped
#define MAKE_ENUM_FLAGS(TEnum)                                                                 \
    inline constexpr bool operator==(TEnum a, std::underlying_type<TEnum>::type b)             \
    {                                                                                          \
        using TUnder = typename std::underlying_type<TEnum>::type;                             \
        return static_cast<TUnder>(a) == b;                                                    \
    }                                                                                          \
    inline constexpr bool operator==(std::underlying_type<TEnum>::type a, TEnum b)             \
    {                                                                                          \
        using TUnder = typename std::underlying_type<TEnum>::type;                             \
        return a == static_cast<TUnder>(b);                                                    \
    }                                                                                          \
    inline constexpr bool operator!=(TEnum a, std::underlying_type<TEnum>::type b)             \
    {                                                                                          \
        using TUnder = typename std::underlying_type<TEnum>::type;                             \
        return static_cast<TUnder>(a) != b;                                                    \
    }                                                                                          \
    inline constexpr bool operator!=(std::underlying_type<TEnum>::type a, TEnum b)             \
    {                                                                                          \
        using TUnder = typename std::underlying_type<TEnum>::type;                             \
        return a != static_cast<TUnder>(b);                                                    \
    }                                                                                          \



M>>На какие грабли можно нарваться?


R>Да грабли могут быть самые разноообразные. Вот из недавнего, например. Был у нас чудо-юдо-супер-говно класс, написанный хрен знает когда для якобы эффективной работы со всякими строками. Объекты этого класса часто использовались в качестве ключей ассоциативных контейнеров. Для этих целей в этом классе был определены операторы сравнения (обычные). И вот, настало время переходить на C++20. Ну, попыхтели-попыхтели и перешли. И, как потом выяснилось, все ассоциативные контейнеры в новой реализации стандартной библиотеке используют уже новый spaceship оператор <=>. Такого оператора в этом классе, конечно же, не было. Зато в этом классе были определены операторы неявного преобразования к char* и const char*, для которых (внезапно) оператор <=> определен. Ну вот эти операторы преобразования и подхватились. И пошло сравнение голых указателей, вместо сравнения содержимого строк. И ведь все успешно откомпилировалось, а ошибку ловили уже в рантайме. А, как известно, чем дурнее ошибка, тем дольше ты ее будешь ловить. И это лишь единичный пример, а вообще, это очень западлистая штука, эти неявные преобразования. И никакой фантазии не хватит, чтоб представить, во что это счастье может вылиться.


Ну вот я подобного и опасаюсь
Маньяк Робокряк колесит по городу
Re: implicit operator bool
От: sergii.p  
Дата: 19.03.24 10:46
Оценка:
Здравствуйте, Marty, Вы писали:

M>На какие грабли можно нарваться?


грабли уже вроде описали. Лично я вообще не выношу оператор bool в стандартной библиотеке. Столько уже ошибок в рантайме отлавливал, когда optional неявно кастится к bool.

Но чтобы грабли наставить можно сделать enum через структуру

struct Enum {
    enum {
        Opt1, Opt2, Opt3
    } _value;
    
    explicit Enum(decltype(_value) value) : _value{value} {}
    operator bool() const noexcept { return _value != Opt1; }
    auto operator<=>(const Enum&) const = default;
};
Re[2]: implicit operator bool
От: Sergey_BG Россия  
Дата: 22.03.24 22:03
Оценка: +1
Здравствуйте, sergii.p, Вы писали:

А почему не
    explicit operator bool()...

?
Сергей
Re[3]: implicit operator bool
От: andrey.desman  
Дата: 22.03.24 22:21
Оценка:
Здравствуйте, Marty, Вы писали:

M>А вот это видимо то, почему я сразу так не сделал, и просто забыл

M>А есть какие-нибудь варианты?

Вариант через класс и на шаблонах, а не на макросах.

Я делал так

#pragma once

#include <initializer_list>
#include <type_traits>

namespace foo
{
  template<typename BitEnum>
  class Flags;
}

/// A class that handles bitmasked enum (preferrably enum class) in a way that it keeps type safety, but
/// provides simplicity and convenience of raw integers.
///
/// \details The enum must consist from bit-masked values, e.g.
/// \code{.cpp}
/// enum class SomeFlags
/// {
///   Flag0 = 0b0001,
///   Flag1 = 0b0010,
///   Flag2 = 0b0100,
///   Flag3 = 0b1000,
/// };
/// \endcode
/// Although multi-bit enum members are allowed and just represent shorthand for common combinations, a care
/// should be taken not to treat them as individual values.
template<typename BitEnum>
class foo::Flags
{
  using UnderlyingType = std::underlying_type_t<BitEnum>;

  template<typename T1, typename... REST>
  constexpr UnderlyingType makeMask(T1 first, REST... rest) const
  {
    static_assert((std::is_same_v<T1, BitEnum> && ... && std::is_same_v<REST, BitEnum>), "Arguments must be of enum type");
    return (UnderlyingType(first) | ... | UnderlyingType(rest));
  }

public:
  constexpr Flags() = default;

  /// Constructs a flag set by combining/disjuncting its' arguments.
  template<typename T1, typename... REST>
  constexpr Flags(T1 first, REST... rest)
    : m_flags(makeMask(first, rest...))
  {
  }

  /// Constructs a flag set by combining/disjuncting flags in passed initializer list.
  constexpr Flags(std::initializer_list<BitEnum> list)
  {
    for (auto flag : list)
      m_flags |= UnderlyingType(flag);
  }

  /// Tells whether any of specified flags are set.
  template<typename T1, typename... REST>
  constexpr bool any(T1 first, REST... rest) const
  {
    return bool(m_flags & makeMask(first, rest...));
  }

  /// Tells whether all of specified flags are set.
  template<typename T1, typename... REST>
  constexpr bool all(T1 first, REST... rest) const
  {
    const auto mask = makeMask(first, rest...);
    return (m_flags & mask) == mask;
  }

  /// Tells whether none of specified flags are set.
  template<typename T1, typename... REST>
  constexpr bool none(T1 first, REST... rest) const
  {
    const auto mask = makeMask(first, rest...);
    return !(m_flags & mask);
  }

  /// Sets specified flags.
  template<typename T1, typename... REST>
  constexpr Flags& set(T1 first, REST... rest)
  {
    m_flags |= makeMask(first, rest...);
    return *this;
  }

  /// Unsets specified flags.
  template<typename T1, typename... REST>
  constexpr Flags& reset(T1 first, REST... rest)
  {
    m_flags &= ~makeMask(first, rest...);
    return *this;
  }

  /// Unsets all flags.
  void clear()
  {
    m_flags = 0;
  }

  constexpr explicit operator bool() const
  {
    return m_flags != 0;
  }

  constexpr bool operator!() const
  {
    return m_flags == 0;
  }

  constexpr operator BitEnum() const
  {
    return BitEnum(m_flags);
  }

  constexpr Flags operator&(Flags r)
  {
    return Flags{BitEnum(m_flags & r.m_flags)};
  }

  constexpr friend Flags operator&(BitEnum l, Flags r)
  {
    return Flags(l) & r;
  }

  constexpr Flags operator|(Flags r)
  {
    return Flags{BitEnum(m_flags | r.m_flags)};
  }

  constexpr friend Flags operator|(BitEnum l, Flags r)
  {
    return Flags(l) | r;
  }

  constexpr Flags& operator&=(Flags r)
  {
    m_flags &= r.m_flags;
    return *this;
  }

  constexpr Flags& operator|=(Flags r)
  {
    m_flags |= r.m_flags;
    return *this;
  }

private:
  UnderlyingType m_flags = 0;
};
Re: implicit operator bool
От: rosencrantz США  
Дата: 23.03.24 00:55
Оценка: :)
Здравствуйте, Marty, Вы писали:

M>уже устал писать


Годы (десятилетия) идут, а у плюсовиков всё те же проблемы

Вы реально все настолько гении, что высокоуровневый дизайн и архитектура никогда не вызывают вопросов, что там перформанс тесты писать не надо, сопровождаемость запредельная — код читается лучше, чем литературный русский язык? Почему половина вопросов в этом форуме это какое-то дрочилово на 5 лишних букв?
Re[2]: implicit operator bool
От: rg45 СССР  
Дата: 23.03.24 22:53
Оценка: +1 -1
Здравствуйте, rosencrantz, Вы писали:

R>Годы (десятилетия) идут, а у плюсовиков всё те же проблемы


R>Вы реально все настолько гении, что высокоуровневый дизайн и архитектура никогда не вызывают вопросов, что там перформанс тесты писать не надо, сопровождаемость запредельная — код читается лучше, чем литературный русский язык? Почему половина вопросов в этом форуме это какое-то дрочилово на 5 лишних букв?


Тебя это в каком месте беспокоит, убогий?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: implicit operator bool
От: rosencrantz США  
Дата: 23.03.24 23:05
Оценка:
Здравствуйте, rg45, Вы писали:

R>Тебя это в каком месте беспокоит, убогий?


Мне для общего развития — вот как раз чтобы не быть таким убогим
Re[4]: implicit operator bool
От: rg45 СССР  
Дата: 23.03.24 23:07
Оценка: -1
Здравствуйте, rosencrantz, Вы писали:

R>Мне для общего развития — вот как раз чтобы не быть таким убогим


Так ты еще не достиг того уровня, чтоб что-то вякать на плюсовых форумах. "Приятные языки" со встроенными памперсами — вот пока твой уровень.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 23.03.2024 23:08 rg45 . Предыдущая версия . Еще …
Отредактировано 23.03.2024 23:08 rg45 . Предыдущая версия .
Re[5]: implicit operator bool
От: rosencrantz США  
Дата: 23.03.24 23:17
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, rosencrantz, Вы писали:


R>>Мне для общего развития — вот как раз чтобы не быть таким убогим


R>Так ты еще не достиг того уровня, чтоб что-то вякать на плюсовых форумах. "Приятные языки" со встроенными памперсами — вот пока твой уровень.


Ты что-то разошёлся с оценками C++ долгое время был моим основным языком — со школы, и первые нескольких лет работы. Я понимаю, что ты обижен и хочешь нахамить. Но вот ты уже 2 грубых сообщения написал — теперь может по делу что-то скажешь?
Re[6]: implicit operator bool
От: rg45 СССР  
Дата: 23.03.24 23:22
Оценка: :)
Здравствуйте, rosencrantz, Вы писали:

R>Ты что-то разошёлся с оценками C++ долгое время был моим основным языком — со школы, и первые нескольких лет работы.


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

template <typename T>
T foo(T&&);

?

R>Я понимаю, что ты обижен и хочешь нахамить. Но вот ты уже 2 грубых сообщения написал — теперь может по делу что-то скажешь?


Судя по твоему бодрому вступлению, ты сюда за этим и пришел, чтоб тебе нащелкали по носу и накрутили тебе твой поросячий хвост. Ну так ты получишь то, за чем пришел.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 23.03.2024 23:43 rg45 . Предыдущая версия . Еще …
Отредактировано 23.03.2024 23:32 rg45 . Предыдущая версия .
Отредактировано 23.03.2024 23:22 rg45 . Предыдущая версия .
Re[7]: implicit operator bool
От: rosencrantz США  
Дата: 23.03.24 23:51
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, rosencrantz, Вы писали:


R>>Ты что-то разошёлся с оценками C++ долгое время был моим основным языком — со школы, и первые нескольких лет работы.


R>Да я могу представить твой уровень. Этот тебе кажется, что ты какой-то уникальный, а я тут таких как ты знаешь сколько повидал.


Ставишь диагноз по аватарке?

R>Ну, например, какой тип результата у функции ниже:

R>
R>T foo(T&&);
R>

R>?

T& ? Я гадаю конечно. Не застал C++11, но не понимаю почему это важно. Мой вопрос ведь — про культуру C++. А она, как мне кажется, не изменилась со времён C++98.

R>Судя, по твоему бодрому вступлению, ты сюда за этим и пришел, чтоб тебе нащелкали по носу и накрутили тебе твой поросячий хвост. Ну так ты получишь то, за чем пришел.


Ты будешь отвечать на вопрос или нет? Если не будешь, мне твои метафоры и эпитеты не интересно читать.
Re[8]: implicit operator bool
От: rg45 СССР  
Дата: 23.03.24 23:57
Оценка: +1 :)
Здравствуйте, rosencrantz, Вы писали:

R>T& ? Я гадаю конечно. Не застал C++11, но не понимаю почему это важно. Мой вопрос ведь — про культуру C++. А она, как мне кажется, не изменилась со времён C++98.


Я тебе об этом и говорю, что ты гадаешь. Ты пришел в область, в которой ни черта не смыслишь и делашь космические заявления, космической же глупости.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 24.03.2024 0:02 rg45 . Предыдущая версия .
Re[9]: implicit operator bool
От: rosencrantz США  
Дата: 24.03.24 00:00
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, rosencrantz, Вы писали:


R>>T& ? Я гадаю конечно. Не застал C++11, но не понимаю почему это важно. Мой вопрос ведь — про культуру C++. А она, как мне кажется, не изменилась со времён C++98.


R>Я тебе об этом и говорю, что ты гадаешь. Ты пришел в область, в которой ни черта не смыслишь и делашь комические заявления, космической же глупости.


Знание некоторых базовых идей освобождает от знания многих конкретных фактов. Так чего, угадал или ты просто хочешь по-джентельменски слиться?
Re[10]: implicit operator bool
От: rg45 СССР  
Дата: 24.03.24 00:03
Оценка: +1
Здравствуйте, rosencrantz, Вы писали:

R>Знание некоторых базовых идей освобождает от знания многих конкретных фактов. Так чего, угадал или ты просто хочешь по-джентельменски слиться?


А кто тебе сказал, что ты знаешь базовые вещи? Ты сам так решил? У меня, например, другое впечатление сложилось.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 24.03.2024 0:04 rg45 . Предыдущая версия .
Re[11]: implicit operator bool
От: rosencrantz США  
Дата: 24.03.24 00:08
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, rosencrantz, Вы писали:


R>>Знание некоторых базовых идей освобождает от знания многих конкретных фактов. Так чего, угадал или ты просто хочешь по-джентельменски слиться?


R>А кто тебе сказал, что ты знаешь базовые вещи? Ты сам так решил? У меня, например, другое впечатление сложилось.


Ты ещё помнишь вопрос, с которого началась эта ветка? Будет что-то по теме, или продолжишь выпендриваться своим знанием актуальных стандартов?
Re[12]: implicit operator bool
От: rg45 СССР  
Дата: 24.03.24 00:12
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>Ты ещё помнишь вопрос, с которого началась эта ветка?


С чего началась ветка
Автор: Marty
Дата: 16.03 00:42
, я отлично помню. А кстати, ты на вопрос ветки не хочешь ответить?

R>Будет что-то по теме, или продолжишь выпендриваться своим знанием актуальных стандартов?


Во-первых, где я тут выпендривался знанием стандартов. А во-вторых, ты не охренел часом? Это кто из нас повыпендирваться сюда пришел?
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 24.03.2024 11:13 rg45 . Предыдущая версия . Еще …
Отредактировано 24.03.2024 0:13 rg45 . Предыдущая версия .
Отредактировано 24.03.2024 0:13 rg45 . Предыдущая версия .
Re[12]: implicit operator bool
От: rg45 СССР  
Дата: 24.03.24 00:16
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>Ты ещё помнишь вопрос, с которого началась эта ветка?


Я с тем же успехом мог бы задать тебе вопрос "почему ты ешь говно по утрам?". Вперед — отвечай.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 24.03.2024 0:16 rg45 . Предыдущая версия .
Re[2]: implicit operator bool
От: rg45 СССР  
Дата: 24.03.24 01:03
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>Вы реально все настолько гении, что высокоуровневый дизайн и архитектура никогда не вызывают вопросов, что там перформанс тесты писать не надо, сопровождаемость запредельная — код читается лучше, чем литературный русский язык? Почему половина вопросов в этом форуме это какое-то дрочилово на 5 лишних букв?


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

А ну-кась, архитектор ты наш, магистр "базовых вещей", а забацай-ка ты нам на каком-нибудь "приятном языке" аналог вот такой простенькой программки:

http://coliru.stacked-crooked.com/a/d6914a45e0aab8ed

#include <concepts>
#include <iostream>

template <size_t N, typename T>
struct Cartesian
{
    T e[N]{};
};

template <size_t N, typename T, typename U>
constexpr auto dot_product(const Cartesian<N, T>& lhs, const Cartesian<N, U>& rhs) {
    return [&]<size_t...I>(std::index_sequence<I...>){
        return ((lhs.e[I] * rhs.e[I]) + ...);
    }(std::make_index_sequence<N>{}); 
}

int main()
{
    {
        constexpr Cartesian<3, int> a{1, 2, 3};
        constexpr Cartesian<3, int> b{6, 7, 8};
        
        static_assert(std::same_as<int, decltype(dot_product(a, b))>);
        static_assert(44 == dot_product(a, b)); // Compile time computation! Result type - int
        
        std::cout << dot_product(a, b) << std::endl;
    }
    {
        constexpr Cartesian<5, int> a{1, 2, 3, 4, 5};
        constexpr Cartesian<5, double> b{6.1, 7.3, 8.0, 9, 10};

        static_assert(std::same_as<double, decltype(dot_product(a, b))>);
        static_assert(130.7 == dot_product(a, b)); // Compile time computation! Result type - double

        std::cout << dot_product(a, b) << std::endl;
    }
}

Очень хочется посмотреть на "литературный язык"

Только желательно без этих ваших ущербных "ну почти". Слабо?
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 24.03.2024 12:58 rg45 . Предыдущая версия . Еще …
Отредактировано 24.03.2024 12:46 rg45 . Предыдущая версия .
Отредактировано 24.03.2024 1:29 rg45 . Предыдущая версия .
Отредактировано 24.03.2024 1:23 rg45 . Предыдущая версия .
Отредактировано 24.03.2024 1:10 rg45 . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.