Как дополнительные круглые скобки могут сказаться на типе переменной? Я, если честно, никогда не задумывался над этим. Нет, я конечно слышал про перегрузку оператора (), но сейчас не об этом. Несколько дней назад мое невнимательное отношение к круглым скобкам привело к ошибке, найти которую удалось не сразу.
Рассмотрим небольшой пример:
#include <stdio.h> class MyClass { public: MyClass(const wchar_t* = 0){}; friend MyClass& operator << (MyClass &left, const wchar_t &ch) { printf("operator\r\n"); return left; }; }; int main() { MyClass cl(); cl << L'A'; return 0; }
Если попытаться его скомпилировать в g++, то будет выведено сообщение:
error: invalid operands of types ‘MyClass()’ and ‘wchar_t’ to binary ‘operator<<‘
cl << L’A’;
или в моем переводе:
ошибка: недопустимые операнды типов ‘MyClass()’ и ‘wchar_t’ бинарного оператора <<.
Данный оператор перегружен вроде бы правильно. Типы операндов тоже вроде как совпадают с типами в его объявлении (так я думал поначалу). К сожалению, я не сразу обратил внимание на «странный» тип «MyClass()» в сообщении об ошибке. Точнее я не обратил внимание на его отличие от ожидаемого «MyClass».
Компилятор, входящий в состав C++ Builder 6 выдает следующее сообщение:
E2087: Illegal use of pointer
или в моем переводе:
недопустимое использование указателя
Но у нас нет указателей. Тоже самое сообщение выдает и компилятор, входящий в состав Embarcadero RAD Studio 10.
Компилятор, входящий в состав Microsoft Visual Studio 2017 Community выдает более содержательную информацию:
Она-то и вскрывает мое заблуждение относительно типа переменной cl. Ошибка в том, что она содержит не экземпляр класса MyClass, как я ожидал, а нечто другое. Что именно? Оказывается, она задает функцию, не имеющую входных параметров и возвращающую экземпляр класса MyClass.
MyClass foo () {return MyClass();}; typeid(cl) == typeid(foo); //true
Для решения нашей проблемы нужно просто убрать лишние круглые скобки в строке 19:
MyClass cl;
Теперь наш пример работает так, как мы того и ждем.