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?
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;
// ...
}