Как работает безопасная идиома bool_type (и безопасная идиома bool)?

#c #safe-bool-idiom

#c #safe-bool-idiom

Вопрос:

Мне указали на «безопасную идиому bool», и после попытки расшифровать, что происходит (объяснение, предоставленное на сайте, было недостаточным, чтобы дать мне понимание того, почему это работает), я решил попытаться разобрать следующий код и попытаться максимально упростить егонасколько это возможно. Сайт предоставил код ниже:

 class Testable {
    bool ok_;
    typedef void (Testable::*bool_type)() const;
    void this_type_does_not_support_comparisons() const {}
  public:
    explicit Testable(bool b=true):ok_(b) {}

    operator bool_type() const {
      return ok_==true ? 
        amp;Testable::this_type_does_not_support_comparisons : 0;
    }
  };
  

Я решил проанализировать ключевую основу ‘bool_type’, учитывая, что, похоже, это то, на чем она сосредоточена. Учитывая следующую строку:

 typedef void (Testable::*bool_type)() const;
  

Можно (не так легко, из-за заключения в квадратные скобки) вывести, что это typedef типа ‘void Testable::*’, который представляет bool_type . Это можно дополнительно продемонстрировать, выполнив следующие изменения и вызовы функций:

 class Testable {
    bool ok_;
    typedef void (Testable::*bool_type)() const;
    void this_type_does_not_support_comparisons() const {}
  public:
    explicit Testable(bool b=true):ok_(b) {}

    bool_type Test; //Added this

    operator bool_type() const {
      return ok_==true ?
        amp;Testable::this_type_does_not_support_comparisons : 0;
    }
  };

int main()
{
    Testable Test;
    int A = Test.Test; //Compiler will give a conversion error, telling us what type .Test is in the process
}
  

Это позволяет нам увидеть, какой тип bool_type:

ошибка: не удается преобразовать ‘void (Testable::*) () const’ в ‘int’ при инициализации

Что показывает, что это действительно тип ‘void (Testable::*)’.

Здесь возникают проблемы:

Если мы изменим следующую функцию:

     operator bool_type() const {
      return ok_==true ? 
        amp;Testable::this_type_does_not_support_comparisons : 0;
    }
  

И превратите его в:

     operator void Testable::* () const //Same as bool_type, right? 
    {
      return ok_==true ? 
        amp;Testable::this_type_does_not_support_comparisons : 0;
    }
  

Это порождает следующие жалобы:

ошибка: ожидаемый идентификатор перед «*»
ошибка токена: «<недопустимый оператор>» объявлен как функция, возвращающая функцию

Таким образом, мои вопросы:

Почему он генерирует эти жалобы, если ‘void (Testable::*) действительно является typedef для bool_type ?

И

Что здесь происходит?

Комментарии:

1. Почему человек ставит один вопрос в заголовок, а затем совсем другой в тексте? Не говоря уже о двух таких очень разных вопросах?

2. В чем вопрос? bool_type это указатель на функцию-член, указывающий на функцию типа void Testable::some_function() const . Нет никакой путаницы «из-за брекетинга» (хотя синтаксис объявления C не совсем воплощение красоты).

3. Я никогда не говорил слово путаница, я просто сказал, что это нелегко вывести (Testable::* bool_type), на первый взгляд, будет выглядеть как указатель на переменную с именем bool_type . За исключением того, что это не так, учитывая, что typedef подразумевает, что последнее используемое слово — typedef после всего, что предшествует ему. Даже если он заключен в квадратные скобки (что противоречит приоритету).

4. @Alf Вопрос в том, почему замена bool_type не работает? А также я не понимаю, чем она отличается от заголовка (что здесь происходит? = Как работает безопасная идиома bool?; Почему она генерирует эти жалобы = как работает bool_type). Я просто думаю, что ты педантичен.

5. @SSight3: заголовок вопроса касается антишаблона (с использованием злых неявных преобразований при использовании метода, подобного методу Рубе Голдберга, чтобы избежать одной конкретной ошибки), в то время как вопросы в тексте касаются только синтаксиса C .

Ответ №1:

Ваши рассуждения здесь ошибочны

 operator void Testable::* () const //Same as bool_type, right? 
  

Это неверно. Тип bool_type, как сообщает нам компилятор в сообщении об ошибке:

‘void (проверяемый::*)()const’

Итак, чтобы заменить его в операторе, вам понадобится что-то вроде

 operator (void (Testable::*)() const) () const
  

если это вообще возможно! Посмотрите, почему даже уродливый typedef является улучшением?

В C 11 у нас также есть новая конструкция explicit operator bool() , которая избавляет нас от этого уродства.

Комментарии:

1. Позвольте мне угадать, explicit заставляет его работать только для bools? Умная идея. И спасибо, что вы действительно ответили на вопрос.

2. s/answering the question/making a really good guess at what the question was/