Почему следующее разрешено компилировать на C++?
#include<iostream>
using namespace std;
class mytest
{
public:
operator int()
{
return 10;
}
operator const int()
{
return 5;
}
};
int main()
{
mytest mt;
//int x = mt; //ERROR ambigious
//const int x = mt; //ERROR ambigious
}
Почему имеет смысл разрешать компилировать разные версии (на основе постоянства) оператора преобразования, если их использование всегда приводит к неоднозначности?
Может кто-нибудь прояснить, что мне здесь не хватает?
Нет правила против бесполезных заявлений. Пытаться исключить все бесполезные конструкции - очень плохая стратегия для языкового дизайна.
@curiousguy Компилятор выдает ошибку для функций, различающихся только типом возвращаемого значения ... это просто частный случай этого сценария ... поэтому следует исключить ошибки
@ code707 По определению функции не могут отличаться только типом возвращаемого значения, и компилятор жалуется на два разных объявления та же функция.





Для преобразования они неоднозначны; но вы можете называть их явно. например
int x = mt.operator int();
const int x = mt.operator const int();
У вас есть идеи, в каких случаях это может иметь смысл?
В реальном мире я ничего не могу придумать.
Может быть, для привязки указателей на функции-члены? У меня нет под рукой синтаксиса ...
@Wolf Да, вы можете это сделать, но я все еще не думаю, что это подходящее использование функции преобразования.
Я думаю, что это следует запретить в стандарте
Не стесняйтесь писать предложение, в котором перечислены типы, которым не разрешено квалифицироваться здесь как const, или с обоснованием того, почему никакие типы (даже сложные, определенные пользователем) не могут быть квалифицированы как const. По-видимому, никто другой не чувствовал себя достаточно сильно по этому поводу, чтобы выполнить работу, но вы могли бы быть одним из них!
why does it make sense to allow different version(based on constness) of conversion operator (to be compiled) when their use always result in ambiguity;
Обычно это не имеет смысла (кроме очень искусственных вариантов использования), и компилятор может вас об этом предупредить:
prog.cc:12:25: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
operator const int()
^
Можете ли вы добавить такой вариант использования?
@Wolf См. Ответ songyuanyao. Вариант использования - продемонстрировать, что вы можете различить разницу, имея возможность вызывать их по отдельности. Вот почему я считаю это искусственным, бесполезным.
И поскольку никто, скорее всего, этого не сделает (по очевидным причинам), не имеет смысла вносить изменение формулировки, которое запрещало бы это. Во всяком случае, это мои 2 цента.
Рассмотрим некоторый шаблонный код, в котором вместо int и const int напрямую вы получаете более сложное вычисление типов, которое, случается, выводит эти типы для некоторых аргументов шаблона.
@ T.C. Может быть, но пример code707 не вводит понятия шаблонов.
Не совсем то же самое, но немного другая подпись: operator const int&() Имеет смысл; если это преобразование, которое, как вы знаете, может происходить часто, и хотите его кэшировать (ну, может быть, не int, а более крупный объект); и если его перемещение стоит дорого по неизвестной причине ... Впрочем, я не видел такого в реальном мире.
Я прихожу к выводу, что явно не разрешено писать операторы диалога, которые отличаются только постоянством их возвращаемого значения. Это слишком дорогой для явного запрета процесса компиляции.
Помните, что функции (члены), которые отличаются только своим возвращаемым типом
class mytest
{
int f();
const int f();
};
запрещены:
error: ‘const int mytest::f()’ cannot be overloaded
Просто операторы преобразования начинаются с operator, что имеет значение.
Тип, так сказать, является частью имени функции преобразования. На самом деле это не две перегрузки с разным типом возврата, это две разные функции.
@StoryTeller, а как насчет того, чтобы добавить это как еще один ответ? Ответы, данные до сих пор, не совсем удовлетворительны ...
Я считаю, что в самом строгом смысле, даже если это не имеет особого смысла для const, это законно.
Существует разница между объявлением функции и типом функции, и они не имеют одинаковых ограничений.
Функция декларации может не отличаться только типом возвращаемого значения или (начиная с C++ 17) спецификацией исключения. Однако о функции тип ничего такого не говорится (насколько мне известно).
Стандартный [class.conv.fct] описывает функции преобразования как имеющие такую-то форму (перечислены три альтернативы), все из которых не выглядят как обычные объявления функций, в частности, совершенно очевидно, что они не имеют возвращаемого типа.
Это заявляет, тип функции - "функция, не имеющая параметра, возвращающая идентификатор типа преобразования", но нигде не упоминается, что функция преобразования декларации имеет такую вещь, как возвращаемый тип. Напротив, три перечисленные альтернативные формы явно не имеют возвращаемого типа.
Поскольку функции преобразования не имеют возвращаемого типа (... в их объявлении), он не может конфликтовать. Так что, я полагаю, в самом строгом, самом педантичном смысле это даже своего рода «законно», независимо от того, имеет ли это смысл или нет.
Если задуматься, то должно быть тоже как-то законно. Класс вполне может иметь более одной функции преобразования в разные вещи (не только отличаясь const). Такой код действительно существует, и иногда в этом есть большой смысл.
Например, у вас может быть класс File, который преобразуется либо в string (имя файла), либо в handle_t (дескриптор операционной системы), если вы хотите использовать какую-то специфичную для ОС или экзотическую функцию, которую ваш класс-оболочка не поддерживает напрямую. (подумайте, writev, tee или epoll?) Это определенно то, что вы ожидаете от работы!
Если, однако, мы будем рассматривать функции преобразования как «просто функции», то они будут отличаться только своим возвращаемым типом, что сделает объявления незаконными. Итак ... это не сработает.
Предположение: никто не позаботился о том, чтобы составить список слегка полезных и совершенно бесполезных случаев, поэтому в стандарте нет правила для этого. Например, создание
const int() volatileможет снова сделать его полезным. Возможно.