Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to typedef the return type of a method from a template class?

I have a templated class Helper which looks like this:

template< typename Mapper >
class Helper
{
public:

   using mappedType = ... ;

};

I would need mappedType to be the type returned by the map(const int&) method in the Mapper class. Given a valid type for Mapper like the following:

class DMapper
{
public:

    double map(const int& val){ ... }
};

Helper<DMapper>::mappedType should be double. Is there a way to do that without instantiating a Mapper?

The closest I got is:

using mappedType = typename std::result_of<
    decltype(&Mapper::map)(Mapper const*, const int&)
>::type;

But type is not defined in this case.

EDIT:

If I can avoid using a dummy argument for the int, that would be even better (in my concrete code, the argument is not that simple).

like image 735
Dr_Sam Avatar asked Nov 17 '16 12:11

Dr_Sam


People also ask

Can we set a class as a return type of a method?

Absolutely, this is possible. This is also quite common - for example, Factory Method pattern can be implemented within a single class, in which case member functions would be returning instances of the class of which they are members.

How to define a template function c++?

Defining a Function TemplateA function template starts with the keyword template followed by template parameter(s) inside <> which is followed by the function definition. In the above code, T is a template argument that accepts different data types ( int , float , etc.), and typename is a keyword.


3 Answers

You can use std::declval to use member functions in decltype without creating an instance:

using mappedType = decltype(std::declval<Mapper>().map(0));

std::declval can be used for arguments as well:

using mappedType = decltype(std::declval<Mapper>().map(std::declval<int>()));
like image 73
rgmt Avatar answered Oct 10 '22 08:10

rgmt


The closest I got is

using mappedType = typename std::result_of<decltype(&Mapper::map)(Mapper const*, const int&)>::type;

You almost got it.

Auto-declared this pointer is not constant in non-constant class methods, so your

decltype(&Mapper::map)(Mapper const*, const int&)

does not match any method in Mapper class. Remove const qualifier from the first argument, and your result_of solution will work without instancing and dummy arguments:

using mappedType = typename std::result_of<
    decltype(&Mapper::map)(Mapper /*no const here*/ *, const int&)
>::type;
like image 27
Sergey Avatar answered Oct 10 '22 09:10

Sergey


Assuming that Mapper::map is not an overloaded method, its return type can be resolved automatically as follows:

template< typename Mapper >
class Helper
{
private:
    template<class R, class... T>
    static R resolveReturnType(R (Mapper::*)(T...));

    template<class R, class... T>
    static R resolveReturnType(R (Mapper::*)(T...) const);

public:
    using mappedType = decltype(resolveReturnType(&Mapper::map));
};
like image 5
Leon Avatar answered Oct 10 '22 10:10

Leon