c++ - Decltype and templates - any way to make decltype machinery less complicated? -
i playing around implementing group_by method in generic way , have maybe implemented it(except doesnt work c arrays), still code looks ugly me...
is there easier way want(+ work containers , c arrays(i dont know how make work c arrays (t t) ) ?
if not obvious im talking types std::multimap... btw know c++14 remove need type 2 times( auto know type write after -> )
// group_by.cpp : defines entry point console application. // #include <iostream> #include <map> #include <deque> #include <cstdint> #include <functional> #include <algorithm> #include <iostream> template<typename cont, typename f > auto group_by (cont c, f f) -> std::multimap< typename std::remove_reference<decltype(*std::begin(c))>::type, decltype(f(*std::begin(c)))> { std::multimap<typename std::remove_reference<decltype(*std::begin(c))>::type , decltype(f(*std::begin(c)))> result; std::for_each(std::begin(c), std::end(c), [&result,&f](typename cont::value_type elem) { auto key = f(elem); result.insert(std::make_pair(key,elem)); } ); return result; } int main() { std::deque<uint64_t> dq; std::deque<uint64_t>::value_type asghuitl; dq.push_back(1); dq.push_back(2); dq.push_back(11); dq.push_back(21); auto result = group_by(dq, [] (uint64_t x){return x%10;}); }
first step: make work c-style arrays.
second step: use range-based loop. less problems / effort.
third step: make bit nicer using template alias.
#include <iostream> #include <map> #include <deque> #include <cstdint> #include <functional> #include <algorithm> #include <iterator> template < typename elem, typename res > using return_type = std::multimap < typename std::remove_reference<elem>::type, res>; template<typename cont, typename f > auto group_by (cont const& c, f const& f) -> return_type < decltype(*std::begin(c)), decltype(f(*std::begin(c))) > { return_type< decltype(*std::begin(c)), decltype(f(*std::begin(c))) > result; for(auto const& e : c) { auto const& key = f(e); result.insert( std::make_pair(key,e) ); // alternatively, just: // result.emplace( f(e), e ); } return result; } int main() { char const foo[] = "hello world"; auto result = group_by(foo, [] (uint64_t x){return x%10;}); } visual-studio-supported version:
template < typename cont, typename f > auto group_by (cont const& c, f const& f) -> std::multimap < typename std::remove_reference<decltype(*std::begin(c))>::type, decltype(f(*std::begin(c))) > { using key_ref = decltype( *std::begin(c) ); using key_type = typename std::remove_reference < key_ref > :: type; using value_type = decltype( f(*std::begin(c)) ); std::multimap < key_type, value_type > result; for(auto const& e : c) { result.emplace( f(e), e ); } return result; } fourth step: use iterators instead of passing container.
#include <iostream> #include <map> #include <deque> #include <cstdint> #include <functional> #include <algorithm> #include <iterator> template < typename elem, typename res > using return_type = std::multimap< typename std::remove_reference<elem>::type, res >; template < typename fwdit, typename f > auto group_by (fwdit beg, fwdit end, f const& f) -> return_type < decltype(*beg), decltype(f(*beg)) > { return_type < decltype(*beg), decltype(f(*beg)) > result; for(fwdit = beg; != end; ++i) { result.emplace( f(*i), *i ); } return result; } int main() { char const foo[] = "hello world"; auto result = group_by( std::begin(foo), std::end(foo), [] (uint64_t x){return x%10;} ); } visual-studio-supported version:
template < typename fwdit, typename f > auto group_by (fwdit beg, fwdit end, f const& f) -> std::multimap < typename std::remove_reference<decltype(*std::begin(c))>::type, decltype(f(*std::begin(c))) > { using key_ref = decltype( *std::begin(c) ); using key_type = typename std::remove_reference < key_ref > :: type; using value_type = decltype( f(*std::begin(c)) ); std::multimap < key_type, value_type > result; for(fwdit = beg; != end; ++i) { result.emplace( f(*i), *i ); } return result; }
Comments
Post a Comment