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 com Element=char
  • Adicionar *output; antes do primeiro operator<< 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

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top