-1

I'd like to wrap cerr and cout inside an object that intentionally throws away everything in the release build. The intention is to make sure that some debug outputs that a developer might have forgotten to remove will not be shown to the user.

class Wrapper {
public:
    Wrapper( std::ostream& os ):mOs(os){}

    template <typename T>
    DebugOnlyOsWrapper&
    operator<<( T&& in ){
        #ifndef NDEBUG
            mOs << std::forward<T>(in);
        #endif
        return *this;           
    }

private:
    std::ostream& mOs;
};


extern DebugOnlyOsWrapper dcout;   
extern DebugOnlyOsWrapper dcerr;

However, I'm getting a "couldn't deduce template parameter 'T'" error when calling the operator as follows:

dcerr << std::endl;

What am I doing wrong? Is it not possible to deduce type from a function pointer?

Note that adding the following operator overloads fixes the problem, however I'd like to limit code duplication as well as understand the nature of the problem.

using CharT = std::ostream::char_type;   
using Traits = std::ostream::traits_type;

Wrapper& operator<<(std::ios_base& (*func)(std::ios_base&) ){
    #ifndef NDEBUG
        mOs << func;
    #endif
    return *this;           
}
Wrapper& operator<<(
        std::basic_ios<CharT,Traits>& 
            (*func)(std::basic_ios<CharT,Traits>&) 
){
    #ifndef NDEBUG
        mOs << func;
    #endif
    return *this;           
}
Wrapper& operator<<(
        std::basic_ostream<CharT,Traits>& 
            (*func)(std::basic_ostream<CharT,Traits>&) 
){
    #ifndef NDEBUG
        mOs << func;
    #endif
    return *this;           
}

Thank you

jlanik
  • 859
  • 5
  • 12
  • related: https://stackoverflow.com/questions/47427695/using-stream-operator-with-stdendl-in-c – mch Jul 05 '18 at 11:59
  • Duplicate, possibly https://stackoverflow.com/questions/51170934/enable-template-only-if-the-return-expression-is-valid/51171146 – StoryTeller - Unslander Monica Jul 05 '18 at 12:02
  • I would say https://stackoverflow.com/questions/51170934/enable-template-only-if-the-return-expression-is-valid/51171146 leads ultimately to the same problem, but the question is different. – jlanik Jul 05 '18 at 12:28

1 Answers1

0

The problem is that std::endl is not a function but a template.

If the following overload exists, the templates of std::endl are deduced within the call of this overload and hence it works.

Wrapper& operator<<(
        std::basic_ostream<CharT,Traits>& 
            (*func)(std::basic_ostream<CharT,Traits>&) 
);

On the other hand the generic template does not contain enough information to resolve the template parameters of std::endl.

Hence finally, I decided to use something like this:

class Wrapper {
public:
    Wrapper( std::ostream& os ):mOs(os){}

    using CharT = std::ostream::char_type;
    using Traits = std::ostream::traits_type;

    template <typename T>
    Wrapper&
    operator<<( T&& in ){
        return impl(std::forward<T>(in));
    }

    DebugOnlyOsWrapper& operator<<(
            std::basic_ostream<CharT,Traits>& 
                (*func)(std::basic_ostream<CharT,Traits>&) 
    ){
        return impl(func);
    }

private:
    template <typename T>
    DebugOnlyOsWrapper& impl( T&& in ){
        #ifndef NDEBUG
            mOs << std::forward<T>(in);
        #endif
        return *this;           
    }
    std::ostream& mOs;
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
jlanik
  • 859
  • 5
  • 12