Search code examples
c++templatestypedefusing-declaration

How can I typedef a bound a member method and then use that type as a template parameter?


I'm trying to bind a method of a class and to pass it as a template parameter to a different class. This type needs to be used in multiple methods, so I tried using a using clause in the class (struct base below). However, I'm not really able to get the type right. These are (most of) what I've tried so far:

#include <functional>
#include <utility>
#include <type_traits>

template <typename T>
struct N
{
    N(T t) {}
};

struct base
{
    float f() const { return 0.f;}

    // using myN = N<decltype(std::bind(&base::f, std::add_pointer_t<std::declval<base> > ) ) >;
    // Error: tries to convert:
    // '_Bind<float (base::*(base*))() const>' to
    // '_Bind<float (base::*(base*&& (*)()))() const>'


    // using myN = N<decltype(std::bind(&base::f, std::declval<std::add_pointer_t<base> > ) ) >;
    // Error: tries to convert: 
    // '_Bind<float (base::*(base*))() const>' to 
    // '_Bind<float (base::*(base**&& (*)()))() const>'

    using myN = N<decltype(std::bind(&base::f, std::remove_reference<std::declval<std::add_pointer_t<base> > > ) ) >;
    // Error: tries to convert:
    // '_Bind<float (base::*(base*))() const>' to
    // '_Bind<float (base::*(std::remove_reference<base*>&& (*)()))() const>'

    void g()
    {
        auto boundMethod = std::bind(&base::f, this);
        myN n(boundMethod); // <-- this is the line with the errors mentioned above.
    }
};

Limitations: I'm restricted to MSVC 2015, c++11. I've been using gcc on godbolt as quick MCVE, but the production project is with MSVC.

How do I get the types to match up?

Edit:

Using max66's solution(s) works for gcc, but fails with MSVC 2015. The error I get is

error C2664:  
'N<std::_Binder<std::_Unforced,float (__thiscall base::* )(void) const,_Ty>>::N(N<std::_Binder<std::_Unforced,float (__thiscall base::* )(void) const,_Ty>> &&)': 
cannot convert argument 1 from  
'std::_Binder<std::_Unforced,float (__thiscall base::* )(void) const,base *const >' to  
'std::_Binder<std::_Unforced,float (__thiscall base::* )(void) const,_Ty>' 

Solution

  • Why not simply std::declval<base *>() ?

    using myN = N<decltype(std::bind(&base::f, std::declval<base *>()))>;
    

    And remember you have to "call" std::declval<Type>, to obtain an object of type Type.

    So std::declval<Type>(), not std::declval<Type>.