Question

I spent some time removing all the uninfluent code and here is my problem.

--- 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;
}

And this is the output file after building with cl and options /D "WIN32" /D "_UNICODE" /D "UNICODE" and running

--- test.txt ---

00414114test

Basically what happens is that the first operator<< call in main is bound to the member method

basic_ostream<char>& basic_ostream<char>::operator<<(
    const void *)

whereas the second one is (correctly) bound to

basic_ostream<char>& __cdecl operator<<(
    basic_ostream<char>&,
    const char *)

thus giving a different output.

This doesn't happen if i do any of the following:

  • Inline File::CreateOutput
  • Change DataOutput with a non-template one with Element=char
  • Add *output; before the first operator<< call

Am i correct in considering this an undesired compiler behavior?

Is there any explanation for this?

Oh, and i'm using VC7 at the moment to test this simplified code but i have tried the original code in VC9 and VC8 and the same thing was happening.

Any help or even a clue is appreciated

Was it helpful?

Solution

Looks like a compiler bug. You might want to try with the latest VC compiler (which at the moment is VC10 Beta2), and if it's not fixed, follow up with the VC team (you'll need a complete self contained repo). If it is fixed, you should just use the work around you found and move on with your life.

OTHER TIPS

It is a compiler bug (not just looks like one) since it produces different call bindings for the two identical statements

    *output << "test"; // Calls wrong overload
    *output << "test"; // Calls right overload!!!

However, the compiler is within its rights to do this, since you have

    void main()

which means that this is not a valid C++ program (void main isn’t permitted in C either, and it has never been valid in C or C++). So, you have been running the result of compiling invalid source code. The result of that can be anything.

The fact that the Visual C++ compiler does not diagnose void main is just another compiler bug.

change

DataOutput *output(file.CreateOutput(false, false));

to

DataOutput* output = file.CreateOutput(false, false); and it might work. But to make this a reasonable lib function you don't have to clean up after you should not return a pointer but an actual object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top