c++decltypefunction-templates

Declaring and naming a type in the function signature so it can be re-used in the function


I have a utility function for transforming an iterable according to a functor:

template<typename Iterable, typename Functor>
auto transform(Iterable const& input, Functor&& transformer) -> std::vector<decltype(transformer(*input.cbegin()))>
{
    std::vector<decltype(transformer(*input.cbegin()))> output;
    std::for_each(
        std::cbegin(input),
        std::cend(input),
        [&output, &transformer](auto const& m) { output.emplace_back(transformer(m)); });
    return output;
}

void test_transform()
{
    std::vector<int> ints { 10, 20, 30 };
    auto transformer = [](int i) { return std::to_string(i + 1); };
    std::vector<std::string> strs = VectorUtil::transform(ints, transformer);
    for (std::string s : strs) { std::cout << s << std::endl; }
}

It's rather ugly to have to write out the return type twice. Is there some way to give a name to either:

decltype(transformer(*input.cbegin()))

or

std::vector<decltype(transformer(*input.cbegin()))>

so it can be re-used?


Solution

  • The most pretty option would be to remove the return type entirely and declare it auto, meaning that the function would have deduced return type. This is most likely fine in your case, but perhaps you cannot do that.

    If you really insist on having a declared return type, there is still the option of simplifying this by using an alias template. std::result_of or std::invoke_result are of no use because they don't give you a nice and short return type, and that seems to be the whole point here.

    template <typename Iterable, typename Functor>
    using transform_result_t =
      std::vector<decltype(std::declval<Functor&>()(*std::declval<Iterable&>().cbegin()))>;
    

    Such an alias template would be usable as follows:

    template<typename Iterable, typename Functor>
    auto transform(Iterable const& input, Functor&& transformer)
      -> transform_result_t<Iterable, Functor>
    {
        transform_result_t<Iterable, Functor> output;
        // ...
    }