0

A sink backend expecting a non-const parameter in its constructor can't be used, as the wrapping sink frontend seems to only forward const parameters.

Example:

class buffering_sink_backend :
    public boost::log::sinks::basic_formatted_sink_backend <
    char,
    boost::log::sinks::synchronized_feeding
    >
{
public:
    buffering_sink_backend(std::string &buffer)
        : _buffer(buffer)
    {}

    void consume(boost::log::record_view const &rec, string_type const &formattedMessage)
    {
        _buffer += formattedMessage;
    }

private:
    std::string &_buffer;
};

typedef boost::log::sinks::synchronous_sink< buffering_sink_backend > buffering_sink;


void main()
{
    std::string buffer;

    buffering_sink *bla = new buffering_sink(buffer);   // --> compiler error: cannot convert argument 1 from 'const std::string' to 'std::string &'
}

Is there any way to provide a custom sink backend with non-const object references or am I doing something conceptually wrong?

4

1 回答 1

0

synchronous_sink does not actually use C++11 variadic templates and perfect forwarding, but instead uses some preprocessor magic to generate a series of forwarding constructors taking const references, so that after macro expansion it becomes

template< typename T0 > 
explicit synchronous_sink( T0 const& arg0) 
         : base_type(false),
           m_pBackend(boost::make_shared< sink_backend_type >( arg0)) {}

/* ... 13 constructors omitted ... */

template< typename T0 , typename T1 , typename T2 , typename T3 , typename T4 ,
          typename T5 , typename T6 , typename T7 , typename T8 , typename T9 ,
          typename T10 , typename T11 , typename T12 , typename T13 , typename T14 > 
explicit synchronous_sink( T0 const& arg0 , T1 const& arg1 , T2 const& arg2 , 
                           T3 const& arg3 , T4 const& arg4 , T5 const& arg5 , 
                           T6 const& arg6 , T7 const& arg7 , T8 const& arg8 ,
                           T9 const& arg9 , T10 const& arg10 , T11 const& arg11 ,
                           T12 const& arg12 , T13 const& arg13 , T14 const& arg14) 
         : base_type(false),
           m_pBackend(boost::make_shared< sink_backend_type >( 
                            arg0 , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 ,
                            arg8 , arg9 , arg10 , arg11 , arg12 , arg13 , arg14)) {}

As a result, if you pass buffer directly to this constructor, it will always be passed by a const reference.

Possible solutions are:

  • Wrap the non-const reference inside a std::reference_wrapper or the boost equivalent.

    #include <functional>  // for std::ref (C++11 only)
                           // or #include <boost/ref.hpp> for boost::ref
    
    buffering_sink *bla = new buffering_sink(std::ref(buffer)); // or boost::ref(buffer)
    
  • Make the backend yourself, and then use the explicit synchronous_sink(shared_ptr< sink_backend_type > const& backend); constructor:

    boost::shared_ptr<buffering_sink_backend> backend = boost::make_shared<buffering_sink_backend>(buffer);
    buffering_sink *bla = new buffering_sink(backend);
    
于 2014-08-22T00:04:29.923 回答