c++templatesreturn-type-deduction

How do write a templated free function depending on return type


I have a problem related to type deduction from a function return value.

First, some context, to show what I expect. Say I have this function template:

template <typename T1, typename T2>
T1 foo( T2 t )
{
    T1 a = static_cast<T1>(t); // dummy conversion,
    return a;                  // just there to use t
}

then, this does not build, because return type can't be used for type deduction:

int a;
float v1 = foo(a);
char  v2 = foo(a);

But if I add the requested type, then it's okay:

int a;
auto v1 = foo<float>(a);
auto v2 = foo<char>(a);

Now my problem. I have a class, that provides a getter to some data:

template<typename T>
struct MyClass
{
   T data;
   template<typename U>
   U get() { return static_cast<U>(data); }  // dummy code, returns an 'U'
};

User code can fetch the data with this (builds fine):

MyClass<int> m;
auto v3 = m.get<float>();

But I want to provide to user code a second way to access the data, by using a free function, so one can write:

MyClass<int> m;
auto v4 = ff_get<float>(m);

The question is: How do I write ff_get()?

I tried:

template <typename T1, typename T2>
T1 ff_get( T2 t )
{
    return t.get<T1>();
}

But this will not build, although it seems to me is uses the same syntax as the foo call above. So second part of the question is: why does this fail?

(see live code)


Solution

  • Convert the return type rather than deduce it

    You can create a conversion proxy object for your return type. This moves the return type deduction into a template conversion operation instead.

    template <typename T>
    struct foofoo {
        T t_;
        foofoo (T t) : t_(t) {}
        template <typename U>
        operator U () const { return static_cast<U>(t_); }
    };
    
    template <typename T>
    foofoo<T> foo( T t )
    {
        return foofoo<T>(t);
    }
    

    Applied to MyClass, your getter could be implemented similarly:

    template<typename T>
    struct MyClass
    {
       T data;
       foofoo<T> get() { return foofoo<T>(data); }
    };
    

    And then, this code would work just fine:

    MyClass<int> m;
    float v3 = m.get();
    

    Deduce the return type of the getter

    Now, to implement ff_get, it is mostly a trivial function implementation, except that the return type is now deduced from the get method itself. In C++11, you would use the trailing return type syntax.

    template <typename T>
    auto ff_get (T t) -> decltype(t.get())
    {
        return t.get();
    }
    

    Starting from C++ 14, you can drop the trailing return type altogether, since there is no ambiguity in the return type.

    template <typename T>
    auto ff_get (T t)
    {
        return t.get();
    }