Visual С++ - оператор преобразования вызовов в примитивном типе явно

Я играл с классом Foo, который определял неявный operator bool(). Я использовал Foo как возвращаемый тип для нескольких функций, поэтому я мог получить информацию о том, что было сделано, и вызвать Foo::operator bool(), чтобы убедиться, что операция выполнена успешно.

Из любопытства я также попробовал явный вызов оператора преобразования при использовании Foo:

if(!func().operator bool()) // func returned Foo
    throw std::logic_error("operation was not successful");

Это сработало нормально. Затем я вдруг решил сбросить класс Foo и перейти с простым bool, но я забыл удалить вызов .operator bool() на возвращаемое значение функции. И поэтому я обнаружил набор странных поведений компилятора Visual С++ 12.0 (Visual Studio 2013).


Ни один из явных вызовов операторов преобразования в bool не действует в GCC:
request for member ‘operator bool’ in ‘true’, which is of non-class type ‘bool’

Теперь поведение, которое я получаю в Visual Studio:

#include <iostream>
using std::cout;
using std::endl;

bool func()
{
    return true;
}

int main()
{
    bool b = true.operator bool();
    cout << b << endl; // error C4700: uninitialized local variable 'b' used

    // evaluates to true (probably like b would do if it compiled)
    if(false.operator bool())
        cout << "a" << endl;

    cout << func().operator bool() << endl; // prints nothing

    int m = 10;
    cout << m.operator int() << endl; // prints nothing

    // correctly gives error: left of '.<' must have class/struct/union
    cout << m.operator <(10) << endl;
}

Даже intellisense прав и показывает Error: expression must have a class type. Есть ли объяснение всему этому? Жук? (Нежелательное) расширение? Что это?

Ответ 1

Приятно найти! Стандарт определенно делает это плохо сформированным с требуемой диагностикой, [expr.ref]:

Постфиксное выражение, за которым следует точка . или стрелка ->, с последующим ключевым словом template (14.2), а затем за которым следует id-выражение, является постфиксным выражением. [..] Для первый вариант (точка) первое выражение должно иметь полный класс тип.

Кроме того, не расширение: было бы адским бессмысленным расширением. Кажется, что VС++ реализует bool с некоторым внутренним (класс-подобным?) Типом:

В Visual С++ 5.0 и более поздних версиях bool реализован как встроенный тип с размером 1 байт.

Этот тип подобной семантике явно не полностью подавлен. Даже

bool b;
b.operator std::string();

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