views:

152

answers:

4

Hi, I am overloading operator << to implement a stream like interface for a class:

template<typename T>
CAudit& operator <<  ( const T& data ) {
    audittext << data;
    return *this;
}

CAudit& operator << ( LPCSTR data ) {
    audittext << data;
    return *this;
}

The template version fails to compile with "fatal error C1001: INTERNAL COMPILER ERROR (compiler file 'msc1.cpp', line 1794)". Non-template functions all compile correctly.

Is this due to VC6s deficiencies when handling templates and is there a way around this?

Thanks, Patrick

EDIT :

the full class is:

class CAudit
{
public:    
/* TODO_DEBUG : doesn't build! 
template<typename T>
CAudit& operator <<  ( const T& data ) {
    audittext << data;
    return *this;
}*/

~CAudit() { write(); }//If anything available to audit write it here

CAudit& operator << ( LPCSTR data ) {
    audittext << data;
    return *this;
}

//overload the << operator to allow function ptrs on rhs, allows "audit << data << CAudit::write;"
CAudit& operator << (CAudit & (*func)(CAudit &))
{
    return func(*this);
}

void write() {
}

//write() is a manipulator type func, "audit << data << CAudit::write;" will call this function
static CAudit& write(CAudit& audit) { 
    audit.write();
    return audit; 
}

private:
std::stringstream audittext;
};

The problem occurs with the function overload of operator << which is used to allow write() to be used as a stream manipulator:

CAudit audit
audit << "Billy" << write;
A: 
 template<typename T>
    CAudit& operator <<  (T data ) {
        audittext << data;
        return *this;
    }

EDIT:

#include <iostream>
using namespace std;

class CAudit{
public:
    CAudit(){}

    template< typename T >
    CAudit &operator<<(T arg);
    CAudit &operator<<(char s);
};

template< typename T>
void oldLog(T arg){
  cout << arg;
}

template< typename T >
CAudit &CAudit::operator<<(T arg){
    oldLog( arg );
    return *this;
}
CAudit &CAudit::operator<<(char arg){
    oldLog( arg );
    return *this;
}
int main(){

    CAudit e;
    e << "Hello";
    e << 'T';

 return 0;
}
adatapost
No, that doesn't make a difference
Patrick
A: 

The problem does not seem to be in the code snippet you posted. This program works fine:

#include "stdafx.h"
#include <string>
#include <iostream>
#include <sstream>
#include <windows.h>

class CAudit {

std::ostringstream audittext;

public:
std::string getAuditText() const { return audittext.str(); }

template<typename T>
    CAudit& operator <<  ( const T& data ) {
    audittext << data;
    return *this;
}


CAudit& operator <<  ( int data ) {
    audittext << data;
    return *this;
}

CAudit& operator << ( LPCSTR data ) {
audittext << data;
return *this;
}
};


int main(int argc, char* argv[])
{
CAudit a;
int i = 123;
const char * s = "abc";

a << i;
a << s;

std::cout << "audittext is: '" << a.getAuditText() << "'\n";
return 0;
}

Could you post some more code?

Ralph
+1  A: 

The kind of error definitely looks like the kind of crashes caused by VC6's pre-previous-standard implementation of templates.

The best advice is of course to upgrade to either VC7.0, 7.1, 8.0, 9.0 or the beta of 10. To compare that to Windows versions, it's still using Windows 98 when Me, 2000, XP, Vista and 7 are available.

Having said that, you can simplify the lookup a lot by a simple trick:

class CAudit {
    template<typename T>
    CAudit& operator<<(T const& t) {
        this->print(t);
        return *this;
    }
private:
    void print(int);
    void print(LPCSTR);
    void print(CAudit & (*func)(CAudit &));
    template<typename T> print(T const&);
};

The hope here is that the first lookup of operator<< finds the single member template. The other operator<< candidates are non-members for other classes and built-ins. They should be unambiguously worse that this template. The second lookup inside your operator only needs to deal with CAudit members called print.

MSalters
This looks right but couldn't get it to work...
Patrick
+1  A: 

That overload of the template for function pointers surely is too much for good old Visual Studio 6. As a workaround you could define a type for your manipulator and overload operator<< for that type. Here's some code:

#include "stdafx.h"
#include <string>
#include <iostream>
#include <sstream>
#include <windows.h>

class CAudit {

    std::ostringstream audittext;
    void do_write() {}

public:
    ~CAudit() { do_write(); } 

    // types for manipulators
    struct Twrite {};

    // manipulators
    static Twrite write;

    // implementations of <<
    template<typename T>
        CAudit& operator <<  ( const T& data ) {
        audittext << data;
        return *this;
    }

    CAudit& operator <<  ( LPCSTR data ) {
        audittext << data;
        return *this;
    }

    CAudit& operator <<  ( Twrite& ) {
        do_write();
        return *this;
    }
};

// static member initialization
CAudit::Twrite CAudit::write;



int main(int argc, char* argv[])
{
    CAudit a;
    int i = 123;
    const char * s = "abc";

    a << i << s << CAudit::write;

    return 0;
}
Ralph
I don't like having to initialise the static member but it does work, thanks
Patrick