1

我正在以一种通用的方式实现 group_by 方法,我可能已经实现了它(除了它不适用于 C 数组),但代码对我来说仍然很丑陋......

有没有更简单的方法来做我想做的事情(+ 让它适用于所有容器和 C 数组(我不知道如何让它适用于 C 数组(TT))?
如果不是很明显我在谈论 std 的类型::multimap ...顺便说一句,我知道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;});

}
4

2 回答 2

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

Visual-Studio 支持的版本:

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

Visual-Studio 支持的版本:

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;
}
于 2013-05-20T02:52:20.900 回答
1

您拥有的代码将适用于几乎没有变化的数组。首先,您需要#include <iterator>, forstd::beginstd::end. 其次,你应该路过const&。最后,一些typedefs 将有助于使函数的其余部分更具可读性。它最终看起来像:

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解决方案可能更“干净”。

于 2013-05-20T01:58:41.730 回答