Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do write a templated free function depending on return type [duplicate]

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)

like image 838
kebs Avatar asked Nov 24 '25 11:11

kebs


1 Answers

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();
}
like image 63
jxh Avatar answered Nov 26 '25 00:11

jxh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!