Operador de conversão definido pelo usuário como argumento para printf
-
21-09-2019 - |
Pergunta
Eu tenho uma classe que definiu um operador definido pelo usuário para um tchar*, como assim
CMyClass::operator const TCHAR*() const
{
// returns text as const TCHAR*
}
Eu quero ser capaz de fazer algo como
CMyClass myClass;
_tprintf(_T("%s"), myClass);
ou até
_tprintf(_T("%s"), CMyClass(value));
Mas ao tentar, o Printf sempre imprime (nulo) em vez do valor. Eu também tentei um operador normal de char*, bem como variações com const etc. ele só funciona corretamente se eu ligar explicitamente no operador ou fazer um elenco, como
_tprintf(_T("%s\n"), (const TCHAR*)myClass);
_tprintf(_T("%s\n"), myClass.operator const TCHAR *());
No entanto, eu não quero lançar. Como isso pode ser alcançado?
Observe que uma possibilidade é criar uma função que tenha um parâmetro de const TCHAR*, para que ele chama o operador TCHAR*, mas isso também não quero implementar.
Solução
Evite operadores de conversão. Eles raramente fazem o que você quer e, em seguida, as chamadas explícitas são dolorosas. Renomear operator const TCHAR*() const
para TCHAR *str() const
.
Outras dicas
O padrão C ++ diz que conversões implícitas como essa não são aplicadas aos parâmetros de elipsis - como o compilador saberia qual a conversão para aplicar? Você terá que executar a conversão explicitamente você mesmo, ou melhor ainda para usar o printf.
Os operadores de conversão são chamados quando o compilador deseja converter um valor em outro tipo. Isso funciona para funções que obtêm parâmetros definidos de tipos específicos. Não funciona para funções variádicas como printf()
com ...
na declaração de função. Essas funções pegam os argumentos e depois trabalham com eles, para que o operador de conversão nunca seja chamado.
Para ser específico, quando o compilador vê printf("%s", foo)
, passa foo
, seja o que for, para printf()
, que terá que assumir que é adequado para um %s
formato como é. Nenhum operador de conversão será chamado (embora certas promoções aritméticas ocorram).
Operadores de conversão em problemas gerais de causa. Ao ter esse operador nessa classe, você complicou a resolução de sobrecarga de função, pois o compilador pode interpretar um CMyClass
Como se fosse um TCHAR *
. Isso pode causar resultados inesperados, fazendo com que o código seja compilado quando você realmente não queria, ou selecionando a função sobrecarregada errada. (Por exemplo, dado CMyClass cmc;
, a expressão cmc + 10
é de repente legal, já que TCHAR * + int
é perfeitamente legítimo aritmético do ponteiro.) A prática usual é rotular essas conversões explicit
.
O elenco é a coisa certa a fazer se você quiser usar as APIs do estilo PrintF e confiar em um operador de conversão (e não vou discutir aqui se você deve ou não usar esses recursos). No entanto, eu usaria elenco estático, por exemplo _tprintf(_T("%s\n"), static_cast<const TCHAR*>(myClass));