2013-05-20 70 views
1

我用一種通用的方式實現GROUP_BY方法玩弄,我已經實現,也許它(除非它不爲C數組的工作),但仍代碼看起來很醜,我...Decltype和模板 - 使decltype機器更簡單的任何方法?

是否有更簡單的方法做我想要什麼(+爲它適用於所有容器和C數組(我不知道如何使它適用於C數組(TT))?
如果它不是顯而易見的談論類型爲std :: multimap。 .. BTW,我知道C++ 14將刪除需要鍵入此2倍(自動會知道的是,現在我們寫後類型 - >)

// group_by.cpp : Defines the entry point for the 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;}); 

} 
+0

如果你希望它爲C數組工作,你需要更換'類型名續:: value_type'在拉姆達。 – Yuushi

+0

啊,對不起...是guestimating的東西,只改變了2個地方:)需要編輯Q,因爲我不能讓它爲陣列工作:) – NoSenseEtAl

+1

猜測C風格的數組,你必須採取' c'由ref(const ref) – dyp

回答

2

第一步:使它適用於C風格的數組。

第二步:使用基於範圍的for循環。更少的問題/努力。

第三步:使用模板別名更好一點。

#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;}); 
} 

視覺工作室支持的版本:

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; 
} 

第四步:使用迭代器而不是傳遞的容器。

#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 i = beg; i != 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;} ); 
} 

視覺工作室支持的版本:

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 i = beg; i != end; ++i) 
    { 
     result.emplace(f(*i), *i); 
    } 

    return result; 
} 
+0

好的答案,但不幸的是,Visual Studio不支持模板別名。 – Yuushi

+0

@Yuushi謝謝你,「固定」。 – dyp

1

你有無線網絡的代碼只需要很少的變化就可以工作。首先,你需要#include <iterator>,對於std::beginstd::end。其次,你應該通過const&。最後,幾個typedef將有助於使該函數的其餘部分更具可讀性。它最終看起來像:

template<typename Cont, typename F > 
auto group_by (const Cont& c, F f) -> 
    std::multimap< typename std::remove_reference<decltype(*std::begin(c))>::type,  
       decltype(f(*std::begin(c)))> 
{ 

    typedef typename std::remove_reference<decltype(*std::begin(c))>::type value_type; 
    typedef decltype(f(*std::begin(c))) result_type; 

    std::multimap<value_type, result_type> result; 
    std::for_each(std::begin(c), std::end(c), 
     [&result,&f](value_type elem) 
    { 
     auto key = f(elem); 
     result.insert(std::make_pair(key,elem)); 
    } 
    ); 
    return result; 
} 

你可以使這不那麼醜陋?好吧,可能不多。你可以利用性狀得到一個什麼樣的(類似於iterator_traits)傳遞的值類型:

template <typename T> 
struct container_traits 
{ 
    typedef typename T::value_type value_type; 
}; 

template <typename T, std::size_t N> 
struct container_traits<T[N]> 
{ 
    typedef T value_type; 
}; 

template <typename T> 
struct container_traits<T*> 
{ 
    typedef T value_type; 
}; 

利用這一點,並std::result_of(需要type_traits):

template<typename Cont, typename F> 
auto group_by (const Cont& c, F f) -> 
    std::multimap< 
     typename container_traits<Cont>::value_type, 
     typename std::result_of<F(typename container_traits<Cont>::value_type)>::type> 
{ 
    typedef typename container_traits<Cont>::value_type value_type; 
    typedef typename 
     std::result_of<F(typename container_traits<Cont>::value_type)>::type result_type; 

    std::multimap<value_type, result_type> result; 
    std::for_each(std::begin(c), std::end(c), 
     [&result,&f](value_type elem) 
    { 
     auto key = f(elem); 
     result.insert(std::make_pair(key,elem)); 
    } 
    ); 
    return result; 
} 

然而,這需要更多的代碼。對於究竟是怎麼回事,命名可能是稍微更清楚,但decltype解決方案可能是「更清潔」的。