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
), подразумевая, что внутренний класс имеет шаблон оператора преобразования.