José D.
José D.

Reputation: 4275

Failed to specialize function template. Overloading operator<<

I'm trying to make a logger which logs to std::cout and to a file. This is my class:

.h file:

class ProblemsManager {
        (...)
private:
        (...)

    class logger {
    private: 
        std::ofstream fileStream;
        static const std::string LOG_PATH;
    public: 
        logger();
        ~logger();


    template<class T> 
    friend logger & operator<<(logger &log, const T & bytes) {
        log.fileStream<<bytes;
        std::cout<<bytes;
        return log;
    }
    };
};

.cpp file

(...)
const std::string ProblemsManager::logger::LOG_PATH = "F:\\Dropbox\\workspace - Visual Studio\\PEuler\\PEuler\\PEuler.log";

ProblemsManager::logger::logger() : fileStream(LOG_PATH,std::ofstream::out) {}
ProblemsManager::logger::~logger() {}

Then if I try to do:

ProblemsManager::logger log;
log<<"test";

I get:

1>f:\dropbox\workspace - visual studio\peuler\peuler\problemsmanager.cpp(47): error C3767: '<<': candidate function(s) not accessible 1> could be the friend function at 'f:\dropbox\workspace - visual studio\peuler\peuler\problemsmanager.h(37)' : '<<' [may be found via argument-dependent lookup]

Upvotes: 1

Views: 161

Answers (3)

There are a couple of issues with your templates, the first is that both differ only on the reference, and that will cause issues. You only want one (that reads and does not write to the argument):

    template<class T> 
    friend logger & operator<<(logger& log, const T & bytes);
    //                                      ^^^^^

Now the second problem is that the templates should be defined somewhere where the compiler can see it when generating the instantiation. That basically means that the definition must be in the header, not in the .cpp file. [*]

Beyond that, since the logger type is private to ProblemsManager, you cannot access it from the namespace level, so you will have issues defining the free function, since it cannot access the nested type. The options would be making the type public, making the function also a friend of ProblemsManager, or as I would recommend, just define the template inline inside the class definition:

class ProblemsManager {
private:
    class logger {
        template<class T> 
        friend logger & operator<<(logger& log, T & bytes) {
           // implementation goes here
        } 
    };
};

[*] This might actually be the exception to the rule, since being a private type, I can only assume that all uses of the logger and thus the operator<< will happen within the translation unit that defines ProblemsManager members. If that is the case, you can disregard this paragraph.

Upvotes: 3

Tomek
Tomek

Reputation: 4659

I'll give it a long shot.

log<<"test";

The above call is a call to operator<< function with the first parameter of logger & and a second of const char[5].

The first overload probably cannot bind as you are overloading on reference and passing const object. The second fails as you are passing array by value and you cannot do that. I am just not sure why your array in not collapsing to a pointer.

Have you tried to overload on const reference? And by the way - why do you overload on value and reference?

Upvotes: 0

Tomek
Tomek

Reputation: 4659

As operator<< functions are not members but friends you cannot use 'this' inside them. You probably want to return 'log' there and appropriately qualify log members with 'log.'.

Upvotes: 0

Related Questions