Deduce return type of function pointer or functor

1.8k Views Asked by At

I'm trying to deduce the return type of a callable type, i.e. a function pointer or a functor.

I previously asked and got an answer showing how to do this for function pointers with hints for how to do this for functors.

Function return type deduction in C++03

Based on that, I have this helper struct which now works for functors but no longer works for function pointers.

// functors
template<class T>
struct Return;
{
    typedef typename T::result_type type;
};

// function pointers
template<class R>
struct Return<R (*)()>
{
        typedef R type;
};

This works for cooperating functors that provide a result_type typedef but not for function pointers. clang gives the following:

error: type 'int (*)(int)' cannot be used prior to '::' because it has no members

typedef typename T::result_type type;

I'm confused by why this isn't a SFINAE error that would move on and catch the specialization of Return.

You can try this yourself and also see some of the context to what I'm doing.

http://coliru.stacked-crooked.com/a/53f4c8c90787e329

Context

This builds on this question.

“Overload” function template based on function object operator() signature in C++98

In that question I was trying to create a function template that will map a std::vector to a new std::vector by using a passed mapping function. Now I'm trying to map from a container that provides a means of iterating over its contents. In the answer to that question the function template had the form:

template<typename F, typename T>
typename expr_check<sizeof(declval<F>()(declval<T>())), std::vector<T> >::type
map_vec(F fnc, const std::vector<T>& source)

Where F is a callable type and T is both the type of the argument taken by type F and also parameterizes the return type, std::vector<T>. See the question for explanation of declval.

Now I want the function template to take a container type, call it C. My thinking is that T should be deduced as the return type of type F here and so is no longer a parameter itself. Right now I'm trying to get the template to work with this signature:

template<typename F, typename C>
typename expr_check<sizeof(declval<F>()(declval<int>())),
        std::vector<typename Return<F>::type> >::type
map_vec(F fnc, const C& source);
2

There are 2 best solutions below

0
On BEST ANSWER

Your error is only specializing for exactly zero arguments.

As pre-C++11 does not have variadic templates, you will have to add one specialization for each count up to your limit.

If you can use C++11 features, just use std::result_of.

0
On

This was a silly mistake that Deduplicator caught.

The working example:

http://coliru.stacked-crooked.com/a/cdb79bbdeedfaa65

The problem was simply that there need to be specializations of Return appropriate for the function signatures that will be used.

// functors
template<class T>
struct Return
{
    typedef typename T::result_type type;
};

// function pointers
template<class R, class T>
struct Return<R (*)(T)>
{
        typedef R type;
};

// function pointers
template<class R, class T, class U>
struct Return<R (*)(T, U)>
{
        typedef R type;
};