VC escolhendo o operador errado << Sobrecarga apenas na primeira chamada. Incomodar?
-
21-09-2019 - |
Pergunta
Passei algum tempo removendo todo o código não influente e aqui está o meu problema.
--- file.h ---
#include <fstream>
#include <string>
template <typename Element>
class DataOutput : public std::basic_ofstream<Element>
{
public:
DataOutput(const std::string &strPath, bool bAppend, bool bBinary)
: std::basic_ofstream<Element>(
strPath.c_str(),
(bAppend ? ios_base::app : (ios_base::out | ios_base::trunc)) |
(bBinary ? ios_base::binary : 0))
{
if (is_open())
clear();
}
~DataOutput()
{
if (is_open())
close();
}
};
class File
{
public:
File(const std::string &strPath);
DataOutput<char> *CreateOutput(bool bAppend, bool bBinary);
private:
std::string m_strPath;
};
--- file.cpp ---
#include <File.h>
File::File(const std::string &strPath)
: m_strPath(strPath)
{
}
DataOutput<char> *File::CreateOutput(bool bAppend, bool bBinary)
{
return new DataOutput<char>(m_strPath, bAppend, bBinary);
}
--- main.cpp ---
#include <File.h>
void main()
{
File file("test.txt");
DataOutput<char> *output(file.CreateOutput(false, false));
*output << "test"; // Calls wrong overload
*output << "test"; // Calls right overload!!!
output->flush();
delete output;
}
E este é o arquivo de saída após a construção com cl
e opções /D "WIN32" /D "_UNICODE" /D "UNICODE"
e correndo
--- test.txt ---
00414114test
Basicamente, o que acontece é que o primeiro operator<<
ligar main
está ligado ao método do membro
basic_ostream<char>& basic_ostream<char>::operator<<(
const void *)
enquanto o segundo está (corretamente) ligado a
basic_ostream<char>& __cdecl operator<<(
basic_ostream<char>&,
const char *)
dando uma saída diferente.
Isso não acontece se eu fizer algum dos seguintes:
- Em linha
File::CreateOutput
- Mudar
DataOutput
com um não-templado um comElement=char
- Adicionar
*output;
antes do primeirooperator<<
ligar
Estou correto ao considerar isso um comportamento indesejado do compilador?
Existe alguma explicação para isso?
Ah, e estou usando o VC7 no momento para testar esse código simplificado, mas tentei o código original em VC9 e VC8 e a mesma coisa estava acontecendo.
Qualquer ajuda ou até uma pista é apreciada
Solução
Parece um bug do compilador. Você pode querer experimentar com o mais recente compilador VC (que no momento é o VC10 Beta2) e, se não for corrigido, acompanhe a equipe do VC (você precisará de um repo completo e independente). Se for corrigido, basta usar o trabalho ao seu redor e seguir em frente com sua vida.
Outras dicas
É um bug do compilador (não apenas parece um), pois produz diferentes ligações de chamadas para as duas declarações idênticas
*output << "test"; // Calls wrong overload
*output << "test"; // Calls right overload!!!
No entanto, O compilador está dentro de seus direitos Para fazer isso, já que você tem
void main()
o que significa que este não é um programa C ++ válido (void main
Também não é permitido em C e nunca foi válido em C ou C ++). Portanto, você está executando o resultado da compilação do código -fonte inválido. O resultado disso pode ser qualquer coisa.
O fato de o compilador visual c ++ não diagnosticar void main
é apenas outro bug do compilador.
mudança
DataOutput *output (file.createOutput (false, false));
para
DataOutput* output = file.createOutput (false, false); E pode funcionar. Mas para tornar isso uma função LIB razoável, você não precisa limpar depois de não devolver um ponteiro, mas um objeto real.