Search code examples
c++c++11typesdecltyperesult-of

C++11 applies result_of on member function, failed, why?


I've got the following code as an experiment:

int f1() { return 0; }

struct Bar {
    Bar() = delete;
    int f() { return 0; }
    int operator()() { return 1; }
};

int main()
{
    decltype(f1()) x = 3;//f1() is expression
    result_of<decltype(&f1)()>::type x1 = 3;//type+param
    result_of<Bar()>::type x3 = 3;//type+param
    decltype(declval<Bar>().f()) y = 4;//expression
    decltype((((Bar*)nullptr)->*(&Bar::f))()) z = 5;//expression

    result_of<decltype(std::mem_fn(&Bar::f))()>::type y2 = 3;//error!!!!!!
}

Everything is OK except the last result_of: I was trying to get the return type of Bar::f, using result_of.

Why it failed, and how to correct it?


Solution

  • The unspecified return type of mem_fn:

    template <class R, class T>
    unspecified mem_fn(R T::* pm) noexcept;
    

    is defined in terms of INVOKE [func.memfn]/p1:

    1 Returns: A simple call wrapper ([func.def]) fn such that the expression fn(t, a2, ..., aN) is equivalent to INVOKE(pm, t, a2, ..., aN) ([func.require]).

    where the definition of INVOKE includes the following two bullets [func.require]/p1:

    Define INVOKE(f, t1, t2, ..., tN) as follows:

    (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and is_base_of<T, decay_t<decltype(t1)>>::value is true;

    ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 does not satisfy the previous two items;

    That is, the first argument of what mem_fn returns must be the type of the implicit object parameter (t1), either a reference or a pointer, e.g.:

    std::result_of<decltype(std::mem_fn(&Bar::f))(Bar&)>::type y2;
    //                                            ~~~^
    
    std::result_of<decltype(std::mem_fn(&Bar::f))(Bar*)>::type y2;
    //                                            ~~~^
    

    You could also remove std::mem_fn altogether:

    std::result_of<decltype(&Bar::f)(Bar*)>::type y2;