4

This question might be related to Why does passing object reference arguments to thread function fails to compile?.

I encountered a similar problem, however, in my case the functor is a template.

class A {
public:
  // Non template version works as expected!!.
  // void operator()(std::ostream& out){
  //    out << "hi\n";
  // }

  // template version doesn't. 
    template <class Ostream>
    void operator()(Ostream& out){
        out << "hi\n";
    }

};

int main() {
   A a;
   thread t(a, ref(cout));
   t.join();
}

GCC says:

error: no match for 'operator<<' in 'out << "hi\012"'

How can I solve this problem?

Community
  • 1
  • 1
Sungmin
  • 2,499
  • 3
  • 26
  • 32
  • Since the thread uses the argument to print something, it seems to implicitly assume the argument is an ostream. Is there really a need for a template here? – jogojapan Dec 26 '12 at 03:45
  • @jogojapan: The reason I tried to make this as a function template is I need to also use some ostreams from boost. boost/iostreams and boost/filesystem. After reading your comment, I tried to pass boost::filesystem::ofstream with non template version, and it works!!. But i am not sure it also works for all other ostreams. – Sungmin Dec 26 '12 at 03:54
  • It will work for anything that is _derived_ from `std::ostream`. For output streams, it is a good idea to be derived from `std::ostream`, and unless you know already of a type of stream you want to use that isn't derived from `std::ostream`, I would, if I were you, assume that taking a `std::ostream &` argument is sufficient. – jogojapan Dec 26 '12 at 04:07

1 Answers1

3

You are passing a std::reference_wrapper. So the type of class Ostream will be std::reference_wrapper which explains the error.

template <class OstreamRef>
void operator()(OstreamRef& outRef){
    outRef.get()<< "hi\n";
}

This should fix it.

With a non template case, when it needs to convert to std::ostream&, the get() is implicitly called. However, with a template there is no need to convert to any other type, so the std::reference_wrapper is passed as-is and thus needs an explicit call to get(). Thanks @jogojapan

Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • Thanks it works. It is my first time to encounter the get() member function. In short, if i pass the reference to the non-template function, I do not need to use get(). However, if i pass the reference to the template function, I should use get(). Does above sentence hold generally? – Sungmin Dec 26 '12 at 04:05
  • 3
    @Sungmin No. You need `get()` because you are dealing with a `std::reference_wrapper` rather than a reference. If your function is not a template, but assumes a `std::ostream &`, the reference-wrapper will automatically be converted to a reference (i.e. `get()` will be called implicitly). But with a template, the compiler sees no reason to convert to `std::ostream &` when instantiating the template, so it leaves it as reference-wrapper. The problem with this solution (i.e. calling `get()` explicitly) is that it only works if you pass in a reference-wrapper (not with `ostream &`). – jogojapan Dec 26 '12 at 04:10