Search code examples
c++debuggingc++14conditional-compilation

Dummy debug class stuck on std::endl overload


I thought I was going to do a quick-and-dirty __DEBUG enabled tracing with something like this:

#ifdef __DEBUG
#   define  dbg std::cout
#   define  err std::cerr
#else

#include <iostream>

class dummy_cout
{
private:

public:
    dummy_cout & operator << ( auto &obj )
    { return *this; }

    dummy_cout & operator << ( std::result_of< decltype( &std::endl ) >::type &obj )
    { return *this; }
};

#   define  dbg dummy_cout()
#   define  err dummy_cout()
#endif


int main( int argc, char *argv[] )
{
    dbg << "Bla, bla. bla..." << std::endl;
}

But it gives me:

cond_dbg.cpp:16:66: error: decltype cannot resolve address of overloaded function
  dummy_cout & operator << ( std::result_of< decltype( &std::endl ) >::type &obj )

I have also tried a half-dozen variations of decltype, result_of, ostream, etc. but I still haven't gotten any step further.

It oughta be simple. If I compile the code defining __DEBUG, I'd have cout and cerr. If I make a normal compilation, I'd have my dummy_cout, that simply does nothing but allows my code to compile without changes and little clutter.

Any help will be greatly appreciated.


Solution

  • You can't write decltype(&std::endl) because std::endl isn't a function, it's a function template:

    template< class CharT, class Traits >
    std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
    

    As such, it doesn't have a type, so it doesn't make sense to ask for it. Moreover, even if it did have a type, the subsequent result_of wrapping wouldn't make any sense.

    The reason that std::cout << std::endl works is that there is an overload that accepts a specific type of function pointer:

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

    This operator is not a function template (it is a member function of basic_ostream, which is a class template), and so overload resolution here triggers instantiation of a specialization of endl.

    To get this to work, you should just do the same thing:

    dummy_cout& operator<<( std::ostream&(*p)(std::ostream&) );
    

    or pick some appropriate CharT and Traits for your dummy type:

    dummy_cout& operator<<( std::basic_ostream<C,T>&(*p)(std::basic_ostream<C,T>& ) );
    

    Just a note. This declaration is ill-formed any C++ standard:

    dummy_cout& operator<<(auto& obj);
    

    Terse function template syntax is a feature of the Concepts TS, which is still a TS. Unless you're using -fconcepts, you need to write:

    template <class T>
    dummy_cout& operator<<(T& obj);