Last active
December 14, 2015 15:28
-
-
Save evanzillians/5107809 to your computer and use it in GitHub Desktop.
comprehense
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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