Make map work without specifying the type

This commit updates `ranget.map` so that the type is inferred from the
return type of the function passed. This makes the usage of `map` less
verbose and makes it more inline with other `ranget` operations like
`filter`.
This commit is contained in:
Thomas Spriggs 2018-11-29 11:42:05 +00:00
parent f7014671b0
commit 7ba5f29533
3 changed files with 15 additions and 10 deletions

View File

@ -441,7 +441,7 @@ void show_compact_goto_trace(
{
auto arg_strings = make_range(step.function_arguments)
.map<std::string>([&ns, &step](const exprt &arg) {
.map([&ns, &step](const exprt &arg) {
return from_expr(ns, step.function, arg);
});

View File

@ -15,6 +15,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com
#define CPROVER_UTIL_RANGE_H
#include <functional>
#include <type_traits>
#include <util/invariant.h>
#include <util/make_unique.h>
@ -300,13 +301,17 @@ public:
return ranget<filter_iteratort<iteratort>>(filter_begin, filter_end);
}
/// Template argument type `outputt` has to be specified when \p f is given as
/// a lambda.
template <typename outputt>
ranget<map_iteratort<iteratort, outputt>>
map(std::function<outputt(const value_typet &)> f)
/// The type of elements contained in the resulting range is deduced from the
/// return type of \p `f`.
template <typename functiont>
auto map(functiont &&f) -> ranget<map_iteratort<
iteratort,
typename std::result_of<functiont(value_typet)>::type>>
{
auto shared_f = std::make_shared<decltype(f)>(std::move(f));
using outputt = typename std::result_of<functiont(value_typet)>::type;
auto shared_f = std::make_shared<
std::function<outputt(const typename iteratort::value_type &)>>(
std::forward<functiont>(f));
auto map_begin =
map_iteratort<iteratort, outputt>(begin(), end(), shared_f);
auto map_end = map_iteratort<iteratort, outputt>(end(), end(), shared_f);

View File

@ -29,8 +29,8 @@ SCENARIO("range tests", "[core][util][range]")
}
THEN("Use map to compute individual lengths")
{
auto length_range = make_range(list).map<std::size_t>(
[](const std::string &s) { return s.length(); });
auto length_range =
make_range(list).map([](const std::string &s) { return s.length(); });
auto it = length_range.begin();
REQUIRE(*it == 3);
++it;
@ -54,7 +54,7 @@ SCENARIO("range tests", "[core][util][range]")
auto range =
make_range(list)
.filter([&](const std::string &s) -> bool { return s[0] == 'a'; })
.map<std::size_t>([&](const std::string &s) { return s.length(); });
.map([&](const std::string &s) { return s.length(); });
// Note that everything is performed on the fly, so none of the filter
// and map functions have been computed yet, and no intermediary container
// is created.