Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ function template: Derived and explicit return type

I have the following problem that I just don't see a proper solution to (and maybe there is none): I have a templated method where the return type is dependent on the input type, and thanks to C++11 decltype the return type can be derive easily, but I would also like to allow the user to define the return type explicitly if desired.

More formally I have a templated function f, that I would like to be callable as f(x), with neither input nor return type explicitly defined. And I would also like to be able to call it as f<ret_t>x() with the return type explicitly defined, but the input type still derived automatically.

Now, satisfying the first constraint with C++11 is easy (let's assume there's another templated method :

template<typename InT>
auto f(const InT& in) -> decltype(/* code deriving the return type using in */);

But this will not allow overriding of the return type, for that I would have to add it as a second template parameter and move the decltype derivation into the template definition and probably need to use std::declval<InT> or std::result_of:

template<
    typename InT,
    typename RetT = /* code deriving return type using InT and declval/result_of */>
RetT f(const InT& in);

However, this way I always need to also explicitly define InT when calling f. So the declaration of f in order to be able to leave InT open but specify RetT should be:

template<
    typename RetT = /* code deriving return type using InT and declval/result_of */,
    typename InT>
RetT f(const InT& in);

But since at the point where I need to specify a default value for RetT, InT is not yet available and hence cannot be used.

The best workaround I could come up with so far, which is not very satisfying and doesn't seem to work anyway since deduction of RetT fails (apparently due to the fact that you cannot deduce the types from default arguments), is:

template<typename RetT, typename InT>
RetT f(
    const InT& in,
    const RetT& = std::declval</* code deriving return type using InT or in and declval/result_of */>());

Are there any better ways to have a default value for RetT that is dependent on InT while still being able to explicitly specify RetT if desired? It's important to note that the return type needs to be available in the function implementation in order for the object of RetT to be allocated directly and only once inside the method body.

like image 463
Janick Bernet Avatar asked Sep 17 '14 11:09

Janick Bernet


Video Answer


1 Answers

You can use std::conditional and a dummy type to check if the function has automatic deduced type or user selected type.

If the user explicitly selects a return type, the return type will be something different from the dummy type and this will be the return type of the function. Otherwise just use the deduced type as before.

Following one example of usage:

#include <typeindex>
#include <type_traits>
#include <iostream>

struct dummy
{
};

template<typename RetType = dummy, typename T>
auto f(const T& in)
-> typename std::conditional<std::is_same<RetType, dummy>::value, T, RetType>::type
{
    std::cout<<typeid(RetType).name()<<" "<<typeid(T).name()<<std::endl;
    return in;
}

int main()
{
    f(1);
    f<float>(1);
}
like image 199
Mircea Ispas Avatar answered Oct 15 '22 19:10

Mircea Ispas