Определяемый пользователем оператор преобразования в качестве аргумента для printf

У меня есть класс, который определил определяемый пользователем оператор для TCHAR*, например

CMyClass::operator const TCHAR*() const
{
    // returns text as const TCHAR*
}

Я хочу иметь возможность сделать что-то вроде

CMyClass myClass;
_tprintf(_T("%s"), myClass);

или даже

_tprintf(_T("%s"), CMyClass(value));

Но при попытке printf всегда печатает (null) вместо значения. Я также пробовал обычный оператор char*, а также варианты с const и т. д. Он работает правильно, только если я явно вызываю оператор или выполняю приведение, например

_tprintf(_T("%s\n"), (const TCHAR*)myClass);
_tprintf(_T("%s\n"), myClass.operator const TCHAR *());

Тем не менее, я не хочу бросать. Как этого добиться?

Обратите внимание, что есть возможность создать функцию с параметром const TCHAR*, чтобы она принудительно вызывала оператор TCHAR*, но это я тоже не хочу реализовывать.


person BC.    schedule 21.03.2010    source источник


Ответы (4)


Избегайте операторов преобразования. Они редко делают то, что вы хотите, и тогда явные вызовы болезненны. Переименуйте operator const TCHAR*() const в TCHAR *str() const.

person Potatoswatter    schedule 21.03.2010
comment
или почему бы не реализовать const TCHAR* operator()() const { }; - person irsis; 22.02.2017

Стандарт С++ говорит, что неявные преобразования, подобные этому, не применяются к параметрам с многоточием - как компилятор узнает, какое преобразование применить? Вам придется выполнить преобразование явно самостоятельно, или, что еще лучше, отказаться от использования printf.

person Community    schedule 21.03.2010
comment
Я бы предпочел прекратить использовать операторы преобразования. - person UncleBens; 21.03.2010
comment
@UncleBens Некоторые преобразования действительно необходимы для написания читаемого кода. где бы мы были без преобразования из char * в строку, например. - person ; 21.03.2010
comment
В его случае направление выглядит как строка в char const*, и в этом случае используется функция-член. Я рекомендую myClass.c_text() или что-то подобное. - person Johannes Schaub - litb; 21.03.2010

Операторы преобразования вызываются, когда компилятор хочет преобразовать значение в другой тип. Это работает для функций, которые принимают определенные параметры определенных типов. Это не работает для функций с переменным числом переменных, таких как printf() с ... в объявлении функции. Эти функции принимают аргументы и затем работают с ними, поэтому оператор преобразования никогда не вызывается.

Чтобы быть точным, когда компилятор видит printf("%s", foo), он передает foo, что бы это ни было, в printf(), который должен предположить, что он подходит для формата %s как есть. Оператор преобразования вызываться не будет (хотя определенные арифметические действия будут иметь место).

Операторы преобразования обычно вызывают проблемы. Имея этот оператор в этом классе, вы усложняете разрешение перегрузки функции, поскольку компилятор может интерпретировать CMyClass, как если бы это был TCHAR *. Это может привести к непредвиденным результатам, либо к компиляции кода, когда вы действительно этого не хотели, либо к выбору неправильной перегруженной функции. (Например, если задано CMyClass cmc;, выражение cmc + 10 неожиданно становится допустимым, поскольку TCHAR * + int является вполне законной арифметикой указателей.) Обычно такие преобразования обозначаются explicit.

person David Thornley    schedule 22.03.2010

Кастинг — это правильное решение, если вы хотите использовать API-интерфейсы в стиле printf и полагаться на оператор преобразования (и я не собираюсь здесь спорить о том, следует ли вам использовать эти функции). Однако я бы использовал статическое приведение, например. _tprintf(_T("%s\n"), static_cast<const TCHAR*>(myClass));

person user1234883    schedule 14.08.2012