c++type-traitsoverloadingdecltyperesult-of

How Can I Use result_of Instead of decltype?


In this answer I create a type trait:

template<typename T>
using to_string_t = decltype(to_string(declval<T>()));

This works just fine but I originally set out to use result_of and now it's irking me that I can't figure out how to do it.

I'm trying to replace the line above with something like this:

template<typename T>
using to_string_t = result_of<to_string(T)>;

But I get a compiler error along the lines of:

error C2275: 'T': illegal use of this type as an expression
note: see declaration of 'T'
error C2974: 'std::result_of': invalid template argument for '_Fty', type expected

I've tried several other inputs to result_of without success, can anyone help me understand what arguments result_of is expecting here?


Solution

  • Let's patch it up. std::result_of expects only types, its result should be retrieve from its type inner typedef, and you need typename to access said typedef because it depends on a template parameter.

    template<typename T>
    using to_string_t = typename std::result_of<decltype(std::to_string)(T)>::type;
                        ^^^^^^^^                ^^^^^^^^                    ^^^^^^
    

    Or in C++14, you can drop ::type and typename :

    template<typename T>
    using to_string_t = std::result_of_t<decltype(std::to_string)(T)>;
                                      ^^
    

    Fine ?

    main.cpp:5:68: error: decltype cannot resolve address of overloaded function
    

    Right, std::to_string is overloaded, so we need to disambiguate it by casting it to one of its overloads.

    template<typename T>
    using to_string_t = typename std::result_of<decltype(static_cast<
    

    Hold on. We need its return type to express the destination type of the cast. We're back to our starting point.

    std::result_of can't deal with overloaded functions, because the function has no definite type until the overload is resolved. decltype is the only solution here, because it does apply overload resolution.

    If you're wondering how std::result_of can be useful, given the above limitation : it's used for overloaded functors, i.e. classes that overload the () operator several times. As the type of the class is known, and does not depend on the call arguments, std::result_of works.

    ... But shouldn't std::to_string always return a std::string ??