Я пытаюсь создать бул обертка структура применения безопасная идиома.
Классическая реализация для решения этой проблемы довольно тривиальна: скелет может выглядеть примерно так:
struct Bool final
{
Bool() = default;
Bool(bool value)
: _value{value}
{}
explicit operator bool() const {
return _value;
}
private:
bool _value{false};
};
То, что я пытаюсь улучшить, это то, как Bool
построен
Например, я хочу избежать неявного сужения по дизайну:
Bool b1(45); // yields warnings, but it compiles
Bool b2{3}; // not ok by standard
Я пытался поранить себя, используя шаблоны, но безуспешно.
Как я мог заставить это работать?
Вы можете достичь этого, явно удалив все остальные конструкторы.
struct Bool final
{
template<class T>
Bool(T) = delete;
Bool(bool value);
};
Добавьте и явно удалите конструктор шаблона:
template <typename T>
Bool(T) = delete;
Это соответствует чему-либо кроме фактического bool
лучше, чем другие конструкторы, и, таким образом, предотвратит неявное преобразование.
Если вам просто нужно:
Переменная, которая является только «истиной» или «ложью» и не может быть неявно преобразована в int / char / pointer, тогда я бы посмотрел на использование класса enum:
enum class Bool {
False,
True,
};
Я пытаюсь спроектировать структуру оболочки bool, применяя идиому безопасной bool.
Не.
Идиома безопасной bool актуальна только в C ++ 03 и более ранних версиях, где, если вы выражаете свой тип как «правдивый», выполняя что-то вроде:
struct A {
operator bool() const;
};
вы столкнетесь с такими проблемами, как:
A{} + 4; // ok?!
A{} < 0; // ok?!
A{} == B{}; // ok if B also has operator bool??!
Таким образом, идиома безопасной bool была решением этой случайной проблемы неявного преобразования, используя указатели на функции (конечно же, указатели на функции!).
В C ++ 11 у нас есть лучше решение:
struct A {
explicit operator bool() const;
};
который делает именно так что мы хотим. На самом деле это было буквально разработан Для решения этой проблемы. И хотя идиома безопасного bool довольно сложная, explicit operator bool
это супер просто в использовании и просто делает правильно. Вам не нужна обертка для нее — на самом деле использовать вашу обертку сложнее, чем написать explicit operator bool
непосредственно.
Более того, ваша обертка накладывает на пользователя (а) неисключаемость, потому что вы сделали Bool
окончательный и (б) дополнительный bool
член, что вы должны держать в синхронизации, так что это вводит, а не решает проблемы. Подумайте, сколько еще работы вам предстоит выполнить:
template <class T>
struct my_unique_ptr : Bool { ... };
против
template <class T>
struct my_unique_ptr {
T* ptr;
explicit operator bool() const { return ptr; }
};