我正在以通用的方式实现group_by方法,我可能已经实现了它(除了它对C数组不起作用),但是代码看起来仍然很丑......
有没有更简单的方法来做我想要的事情(+它适用于所有容器和C数组(我不知道如何让它适用于C数组(T T))?
如果不是很明显我在谈论std :: multimap的类型......
顺便说一下,我知道C ++ 14将删除需要输入2次(auto会知道现在我们写的是什么类型 - >)
// 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 :(得分: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;
}
答案 1 :(得分:1)
您拥有的代码将适用于几乎没有变化的数组。首先,您需要#include <iterator>
,std::begin
和std::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
解决方案可能“更清洁”。