Подтвердить что ты не робот

С++ безопасная обертка bool

Я пытаюсь создать структуру оболочки bool, применяя безопасную идиому bool.
Классическая реализация для решения этого довольно тривиальная: скелет может быть примерно таким:

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

Я пытался причинить себе боль, используя шаблоны, но безуспешно.

Как я могу заставить его работать?

4b9b3361

Ответ 1

Это можно сделать, явно удалив все остальные конструкторы.

struct Bool final
{
    template<class T>
    Bool(T) = delete;

    Bool(bool value);
};

Ответ 2

Добавить и явно удалить конструктор шаблона:

template <typename T>
Bool(T) = delete;

Он соответствует любому другому, кроме фактического bool, лучше, чем другие конструкторы, и таким образом предотвращает неявное преобразование.

Ответ 3

Если вам просто нужно:
Переменная, которая является только "истиной" или "ложной" и не может быть неявно преобразована в int/ char/pointer, тогда я бы посмотрел на использование класса enum:

enum class Bool {
    False,
    True,
};

Ответ 4

Я пытаюсь создать структуру обертки bool, применяя безопасную идиому bool.

Не.

Безопасная идиома bool применима только в С++ 03 и более ранних версиях - если вы выражаете, что ваш тип "правдивый", делая что-то вроде:

struct A {
    operator bool() const;
};

у вас возникли бы такие проблемы, как:

A{} + 4;    // ok?!
A{} < 0;    // ok?!
A{} == B{}; // ok if B also has operator bool??!

Таким образом, безопасная идиома bool была решением этой случайной проблемы неявного преобразования, используя указатели функций (конечно, указатели на функции!).

В С++ 11 у нас есть лучшее решение:

struct A {
    explicit operator bool() const;
};

который делает именно то, что мы хотим. Фактически, это было буквально разработано для решения этой проблемы. И в то время как безопасная идиотка bool - довольно сложная конструкция, explicit operator bool очень проста в использовании и просто делает правильную вещь. Для этого вам не нужна оболочка - на самом деле сложнее использовать вашу обертку, чем напрямую писать explicit operator bool.

Кроме того, ваша оболочка накладывает на пользователя (a) неизбираемость, потому что вы сделали Bool final и (b) добавочный элемент Bool, который вам нужно синхронизировать, поэтому он вводит, а не решает проблемы, Подумайте, сколько еще потребуется для вас выполнить:

template <class T>
struct my_unique_ptr : Bool { ... };

против

template <class T>
struct my_unique_ptr {
    T* ptr;

    explicit operator bool() const { return ptr; }
};