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)
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();
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();
}