Search code examples
c++operator-overloadingargument-dependent-lookupusing-declaration

override an overload selected by ADL


I'm using a library with a defective operator<<, which I want to replace with my own version. It follows the idiom where ADL selects the overload based on the argument's membership in the library's namespace. Is there any way to cause C++ to select my own operator<< instead?


Solution

  • One suboptimal solution is to declare a wrapper class around the library type.

    A general implementation would look like this:

    /* Namespace-specific reference wrapper type.
       Associates a function argument with the desired namespace.
       Declare a new use_local_t for each namespace with an overriding overload */
    template< typename t >
    struct use_local_t
        { t ref; };
    
    template< typename t >
    use_local_t< t && >
    use_local( t &&o )
        { return { std::forward< t >( o ) }; }
    
    /* The overriding overload.
       Instead of overloading on a specialization of use_local_t, use the
       general template and enable_if. This allows for the various kinds of
       references that use_local_t might forward, and conversion of the function
       argument to the expected library_type parameter. */
    template< typename t >
    inline
    typename std::enable_if<
        std::is_convertible< t, library_type const & >::value,
        std::ostream &
    >::type
    operator<< ( std::ostream &s, use_local_t< t > ul ) {
        return s << ul.ref.foo;
    }
    
    std::cout << my_namespace::use_local( library_obj );
    

    This is tested to work with expression templates. Note that if the override overload doesn't match, the error message from GCC 4.7 is a red herring… it refers to an overload in std:: involving a stream rvalue reference:

    /opt/local/include/gcc47/c++/ostream:600:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&)