Search code examples
c++templatesconstantsmember-pointers

reduce number of template specializations while using member pointer to const and non-const method


I have some template code which takes a shared pointer to a class and call a function or method. The problem comes up, if the called method is defined as const.

Example:

struct Y {}; 
struct X
{
        const Y Go() const { return Y{}; }
        const Y Go2() { return Y{}; }
};

Y f1( std::shared_ptr<X>  ) { return Y{}; }

template< typename FUNC, typename ... ARGS >
auto Do( std::shared_ptr<X>& ptr, FUNC&& f, ARGS&& ... args )
{
    return f( ptr, std::forward<ARGS>(args)... );
}

template < typename CLASS, typename RET, typename ... ARGS>
auto Do( std::shared_ptr<X>& base_ptr, RET (CLASS::*mem_ptr)( ARGS...), ARGS&& ... args )->RET
{
    return (base_ptr.get()->*mem_ptr)( std::forward<ARGS>(args)...);
}

// Any chance to avoid the full duplication of the code here
// to define the member pointer to a const method?

template < typename CLASS, typename RET, typename ... ARGS>
auto Do( std::shared_ptr<X>& base_ptr, RET (CLASS::*mem_ptr)( ARGS...) const, ARGS&& ... args )->RET
{
    return (base_ptr.get()->*mem_ptr)( std::forward<ARGS>(args)...);
}

int main()
{
    auto xptr = std::make_shared<X>();
    Y y1 = Do( xptr, &X::Go );
    Y y2 = Do( xptr, &X::Go2 );
    Y y3 = Do( xptr, &f1 );
}

My problem is the last specialization with the RET (CLASS::*mem_ptr)( ARGS...) const. I simply want to stop duplication the whole code only for the const. In real world code the function calls again another templated one, which results in duplicating a lot of code here.

Any chance to get rid of the specialization for the const member pointer?


Solution

  • You might do:

    template< typename FUNC, typename ... ARGS >
    auto Do( std::shared_ptr<X>& ptr, FUNC&& f, ARGS&& ... args )
    -> decltype((f(ptr, std::forward<ARGS>(args)... )))
    {
        return f( ptr, std::forward<ARGS>(args)... );
    }
    
    template<typename MemberF, typename ... ARGS>
    auto Do(std::shared_ptr<X>& base_ptr, MemberF mem_ptr, ARGS&& ... args)
    -> decltype((base_ptr.get()->*mem_ptr)( std::forward<ARGS>(args)...))
    {
        return (base_ptr.get()->*mem_ptr)( std::forward<ARGS>(args)...);
    }