Определенный пользователем оператор преобразования в качестве аргумента для printf
-
21-09-2019 - |
Вопрос
У меня есть класс, который определяет определяемый пользователем оператор для 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*, но я тоже не хочу это реализовывать.
Решение
Избегайте операторов преобразования.Они редко делают то, что вы хотите, и тогда явные призывы болезненны.Переименовать operator const TCHAR*() const
к TCHAR *str() const
.
Другие советы
В стандарте C++ указано, что подобные неявные преобразования не применяются к параметрам с многоточием. Откуда компилятору знать, какое преобразование следует применить?Вам придется выполнить преобразование самостоятельно или, что еще лучше, прекратить использование printf.
Операторы преобразования вызываются, когда компилятор хочет преобразовать значение в другой тип.Это работает для функций, которые принимают определенные параметры определенных типов.Это не работает для переменных функций, таких как printf()
с ...
в объявлении функции.Эти функции принимают аргументы и затем работают с ними, поэтому оператор преобразования никогда не вызывается.
Точнее, когда компилятор видит printf("%s", foo)
, оно проходит foo
, что бы это ни было, чтобы printf()
, который должен будет предположить, что он подходит для %s
формат как есть.Оператор преобразования вызываться не будет (хотя определенные арифметические действия будут иметь место).
Операторы преобразования обычно вызывают проблемы.Имея этот оператор в этом классе, вы усложняете разрешение перегрузки функции, поскольку компилятор может интерпретировать CMyClass
как если бы это было TCHAR *
.Это может привести к неожиданным результатам: либо вызвать компиляцию кода, когда вы этого действительно не хотите, либо выбрать неправильную перегруженную функцию.(Например, учитывая CMyClass cmc;
, выражение cmc + 10
внезапно становится законным, поскольку TCHAR * + int
является совершенно законной арифметикой указателей.) Обычно такие преобразования обозначаются как explicit
.
Приведение — это правильно, если вы хотите использовать API-интерфейсы в стиле printf и полагаться на оператор преобразования (и я не собираюсь здесь спорить, следует ли вам использовать эти функции).Однако я бы использовал статическое приведение, например. _tprintf(_T("%s\n"), static_cast<const TCHAR*>(myClass));