7 Replies - 659 Views - Last Post: 15 March 2011 - 07:15 PM Rate Topic: -----

#1 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Non-matching template error

Posted 14 March 2011 - 04:00 PM

So in another thread I posted a code example for a simple logging class. I of course compiled and ran the program using VS but when I tried to compile with MinGW I get the following errors:

> "C:\MinGW\bin\g++.exe" "C:\CProjects\Forum Help\LoggerExample.cpp" -std=c++0x -Wall -o LoggerExample.exe
C:\CProjects\Forum Help\LoggerExample.cpp: In function 'int main()':
C:\CProjects\Forum Help\LoggerExample.cpp:81:1: error: no match for 'operator<<' in 'MyLogger((LogLevel)1u) << ": C:\\CProjects\\Forum Help\\LoggerExample.cpp"'
C:\CProjects\Forum Help\LoggerExample.cpp:82:1: error: no match for 'operator<<' in 'MyLogger((LogLevel)0u) << ": C:\\CProjects\\Forum Help\\LoggerExample.cpp"'
C:\CProjects\Forum Help\LoggerExample.cpp:85:1: error: no match for 'operator<<' in 'MyLogger(((LogLevel)i)) << ": C:\\CProjects\\Forum Help\\LoggerExample.cpp"'
C:\CProjects\Forum Help\LoggerExample.cpp:90:1: error: no match for 'operator<<' in 'MyLogger((LogLevel)1u) << ": C:\\CProjects\\Forum Help\\LoggerExample.cpp"'
C:\CProjects\Forum Help\LoggerExample.cpp:96:1: error: no match for 'operator<<' in 'MyLogger(logLevel) << ": C:\\CProjects\\Forum Help\\LoggerExample.cpp"'



in Borland the error becomes:
LoggerExample.cpp 81: 'operator<<' not implemented in type 'MyLogger' for arguments of type 'char *' in function main()

So there has to be something wrong with my template operator function:
#include <iostream>
#include <streambuf>
#include <ostream>
#include <fstream>

using namespace std;


/** <Gleened from the internet> - unknown author **/
template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
    typename traits::int_type overflow(typename traits::int_type c)
    {
        return traits::not_eof(c); // indicate success
    }
};

template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
    private:
    basic_nullbuf<cT, traits> m_sbuf;

    public:
    basic_onullstream():
    std::basic_ios<cT, traits>(&m_sbuf),
    std::basic_ostream<cT, traits>(&m_sbuf)
    {
        init(&m_sbuf);
    }

};

typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;

onullstream nout;
/** </Gleened from the internet>**/

enum LogLevel {
    LOG_NONE,
    LOG_ERROR,
    LOG_WARNING,
    LOG_INFO,
    LOG_NUM_LEVELS
};

const char * LoggingLevels[] = {
    "",
    "ERROR",
    "WARNING",
    "INFO",
};

        

class MyLogger {
    static ostream *logout;
    public:
    static void setLogStream(ostream& os) { logout = &os; }

    LogLevel thisLevel;

    explicit MyLogger(LogLevel level = LOG_NONE) : thisLevel(level) { }

    ostream& logStream() { return (thisLevel == LOG_NONE || logout == NULL) ? nout : *logout; }
};

ostream* MyLogger::logout = NULL;

template<typename T>
ostream& operator<<(MyLogger &mlog, const T& data) {
    return (mlog.logStream() << LoggingLevels[mlog.thisLevel] << data);
}


#define LOG(level) (MyLogger(level) << ": " __FILE__  << "(" << __LINE__ << "): ")

int main() {
    MyLogger::setLogStream(cout);
    
    LOG(LOG_ERROR) << "I don't know what is going on here" << endl;
    LOG(LOG_NONE) << "This should not print" << endl;
    
    for(int i = LOG_NONE; i < LOG_NUM_LEVELS; i++) {
        LOG(static_cast<LogLevel>(i)) << "Testing different logging levels(" << i << ")" << endl;;
    }
    
    ofstream logfile("TestLog.log");
    if (!logfile) {
        LOG(LOG_ERROR) << "Could not open log file" << endl;
    }
    MyLogger::setLogStream(logfile);
    
    LogLevel logLevel = LOG_INFO;
    
    LOG(logLevel) << "This should be redirected to a file" << endl;

    logfile.close();
    return 0;
}


any ideas?

Is This A Good Question/Topic? 0
  • +

Replies To: Non-matching template error

#2 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Non-matching template error

Posted 14 March 2011 - 05:22 PM

Well I fixed it now maybe someone can explain to me WHY the template had to be:

template<typename T>
ostream& operator<<(const MyLogger &mlog, const T& data) {
    return (mlog.logStream() << LoggingLevels[mlog.thisLevel] << data);
}


Why did the MyLogger class have to be a constant reference?

<edit>adding code</edit>

#include <iostream>
#include <streambuf>
#include <ostream>
#include <fstream>
#include <string>

using namespace std;


/** <Gleened from the internet> - unknown author **/
template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
    typename traits::int_type overflow(typename traits::int_type c)
    {
        return traits::not_eof(c); // indicate success
    }
};

template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
    private:
    basic_nullbuf<cT, traits> m_sbuf;

    public:
    basic_onullstream():
    std::basic_ios<cT, traits>(&m_sbuf),
    std::basic_ostream<cT, traits>(&m_sbuf)
    {
        init(&m_sbuf);
    }

};

typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;

onullstream nout;
/** </Gleened from the internet>**/

enum LogLevel {
    LOG_NONE,
    LOG_ERROR,
    LOG_WARNING,
    LOG_INFO,
    LOG_NUM_LEVELS
};

const char * LoggingLevels[] = {
    "",
    "ERROR",
    "WARNING",
    "INFO",
};

        

class MyLogger {
    static ostream *logout;
    public:
    static void setLogStream(ostream& os) { logout = &os; }

    LogLevel thisLevel;

    explicit MyLogger(LogLevel level = LOG_NONE) : thisLevel(level) { }

    ostream& logStream() const { return (thisLevel == LOG_NONE || logout == NULL) ? nout : *logout; }
};

ostream* MyLogger::logout = NULL;

template<typename T>
ostream& operator<<(const MyLogger &mlog, const T& data) {
    return (mlog.logStream() << LoggingLevels[mlog.thisLevel] << data);
}

#define LOG(level) MyLogger(level) << ": " __FILE__  << "(" << __LINE__ << "): "

int main() {
    MyLogger::setLogStream(cout);
    
    LOG(LOG_ERROR) << "I don't know what is going on here" << endl;
    LOG(LOG_NONE) << "This should not print" << endl;
    
    for(int i = LOG_NONE; i < LOG_NUM_LEVELS; i++) {
        LOG(static_cast<LogLevel>(i)) << "Testing different logging levels(" << i << ")" << endl;;
    }
    
    ofstream logfile("TestLog.log");
    if (!logfile) {
        LOG(LOG_ERROR) << "Could not open log file" << endl;
    }
    MyLogger::setLogStream(logfile);
    
    LogLevel logLevel = LOG_INFO;
    
    LOG(logLevel) << "This should be redirected to a file" << endl;

    logfile.close();
    return 0;
}

Was This Post Helpful? 0
  • +
  • -

#3 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Non-matching template error

Posted 15 March 2011 - 10:45 AM

Quote

Well I fixed it now maybe someone can explain to me WHY the template had to be:

template<typename T>
ostream& operator<<(const MyLogger &mlog, const T& data) {
    return (mlog.logStream() << LoggingLevels[mlog.thisLevel] << data);
}


Ok so it has something to do with the instantiation:

    MyLogger inflog(LOG_INFO);
    
    inflog << ": This has no problem";
    MyLogger(LOG_ERROR) << ":  But this does not work";


My brain is tingling about r-value's but I can't seem to find anything that really makes sense. It is not like the second version creates a constant MyLogger -- But for some reason or another the compiler can't make a copy to pass to the function.

Side Note: The code is actually better with the const in -- I am just trying to understand WHY it is needed.
Was This Post Helpful? 0
  • +
  • -

#4 jimblumberg  Icon User is offline

  • member icon


Reputation: 4002
  • View blog
  • Posts: 12,347
  • Joined: 25-December 09

Re: Non-matching template error

Posted 15 March 2011 - 12:02 PM

The only thing I can think of is the possibility that you are returning a const reference from the temporary object. I found this link and by changing your class and the #define I was able to compile and run your program without the constant. I added MyLogger& ref() { return *this;} to your class and changed the #define to #define LOG(level) (MyLogger(level).ref()) << ": " __FILE__ << "(" << __LINE__ << "): ", and removed the const qualifier ostream& operator<<( MyLogger &mlog, const T& data){ .

Jim
Was This Post Helpful? 2
  • +
  • -

#5 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Non-matching template error

Posted 15 March 2011 - 01:09 PM

Given the information in your link I found this stack overflow thread with some quotes from the standard... pretty strange stuff but I think I am beginning to get a picture of what is going on here.

Still need to solidify things though.
Was This Post Helpful? 0
  • +
  • -

#6 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Non-matching template error

Posted 15 March 2011 - 01:19 PM

@jimblumberg -- I wish I could add a second thanks for your link! Its like playing mine sweeper where clearing one square cascades -- I am learning so much just from the one little insight!

It turns out that the little "ref()" trick from DD seems pretty popular as that particular pattern comes up quite a bit.

I plan to write a nice blog about this when I distill it all down into an understanding.
Was This Post Helpful? 0
  • +
  • -

#7 jimblumberg  Icon User is offline

  • member icon


Reputation: 4002
  • View blog
  • Posts: 12,347
  • Joined: 25-December 09

Re: Non-matching template error

Posted 15 March 2011 - 01:50 PM

Glad I was able to help. Let me know when you "distill it all down into an understanding". I would like to see your thoughts about this issue. I'm still not sure I completely understand it yet myself.


Jim

This post has been edited by jimblumberg: 15 March 2011 - 01:54 PM

Was This Post Helpful? 1
  • +
  • -

#8 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Non-matching template error

Posted 15 March 2011 - 07:15 PM

I am still in the process of grokking this but as far as I can tell:

My initial error was triggered because an rvalue (temporary variable) can not be implicitly bound to a modifiable lvalue. Consider this bit of code:

void foo(int& arg) { arg++; }
...
i = 0;
foo(i++);
cout << i;


What value gets displayed? Well we are tying to pass i before it gets incremented, which is an rvalue (a temporary value of an expression) and it has no address to "reference". This kind of thing is not allowed because the temporary value is not guaranteed to have an address and it will cease to exist at the end of the expression and so even if there were an address (the compiler will make one if it needs one) assigning that address to anything persistent(an lvalue) is dangerous.

However if the compiler knows that the rvalue will not be modified it can make a persistent copy.


Of course if you really want to force the compiler to give you an address you can. This becomes important when you are dealing with objects which may have side-effects that require the internal state of the object to change. SO there are work arounds that let you explicitly ask for a reference (thus your example).

Now I am only been ruminating on this information for a few hours between work and "having a baby school" so I may not have fully grasped the deeper nature here.

Here are some additional links:

Visual C++ Team Blog: rvalue references

wikipedia lvalue/rvalue
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1