Skip to content

Instantly share code, notes, and snippets.

@evanzillians
Last active December 14, 2015 15:28
Show Gist options
  • Save evanzillians/5107809 to your computer and use it in GitHub Desktop.
Save evanzillians/5107809 to your computer and use it in GitHub Desktop.
comprehense
#include <iostream>
#include <iterator>
#include <list>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
template<typename container_type, typename transformer_type>
auto comprehense(container_type&& c, transformer_type&& t) -> typename std::remove_cv<typename std::remove_reference<container_type>::type>::type
{
using is_move_source = std::is_rvalue_reference<typename std::add_rvalue_reference<container_type>::type>;
using target_type = typename std::remove_cv<typename std::remove_reference<container_type>::type>::type;
using source_value_type = typename std::remove_reference<decltype(*begin(c))>::type;
using forward_type = typename std::conditional<
!is_move_source::value || std::is_const<source_value_type>::value,
typename std::add_lvalue_reference<source_value_type>::type,
typename std::add_rvalue_reference<source_value_type>::type
>::type;
target_type result;
for (auto&& v : c)
result.emplace(
result.end(),
t(static_cast<forward_type>(v))
);
return result;
}
class Object
{
public:
explicit Object(int v) : value(v) {}
Object(const Object& ref) : value(ref.value) {}
Object(Object&& ref) : value(ref.value)
{
ref.value = 0;
}
Object& operator=(Object&& ref)
{
value = ref.value;
ref.value = 0;
return *this;
}
int value;
};
template<typename container_type>
void dump_values(const std::string& prefix, const container_type& c)
{
std::cout << prefix << ' ';
for (const auto& v : c)
std::cout << v.value << ", ";
std::cout << c.size() << std::endl;
}
struct ObjectTransformer
{
template<typename value_type>
auto operator()(value_type&& v) -> typename std::remove_cv<typename std::remove_reference<value_type>::type>::type
{
using result_type = typename std::remove_cv<typename std::remove_reference<value_type>::type>::type;
result_type result(std::forward<value_type>(v));
result.value += 1;
return std::move(result);
}
};
template<typename container_type, typename transformer_type>
void test_comprehense(const std::string& prefix, container_type&& c, transformer_type&& t)
{
std::cout << prefix << std::endl;
dump_values(" pre-origin:", c);
auto r = comprehense(
std::forward<container_type>(c),
std::forward<transformer_type>(t)
);
dump_values("post-origin:", c);
dump_values("post-new :", r);
std::cout << std::endl;
}
int main()
{
{
const std::list<Object> c1({ Object(1), Object(2), Object(3) });
std::list<Object> c2({ Object(1), Object(2), Object(3) });
test_comprehense("const l-value reference version", c1 , ObjectTransformer());
test_comprehense("const r-value reference version", std::move(c1), ObjectTransformer());
test_comprehense(" l-value reference version", c2 , ObjectTransformer());
test_comprehense(" r-value reference version", std::move(c2), ObjectTransformer());
}
{
const std::vector<Object> c1({ Object(1), Object(2), Object(3) });
std::vector<Object> c2({ Object(1), Object(2), Object(3) });
test_comprehense("const l-value reference version", c1 , ObjectTransformer());
test_comprehense("const r-value reference version", std::move(c1), ObjectTransformer());
test_comprehense(" l-value reference version", c2 , ObjectTransformer());
test_comprehense(" r-value reference version", std::move(c2), ObjectTransformer());
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment