C++ 在函数模板中使用lambda,can';t推断类型,makeSet()用例
我想要实现的是一个makeSet()函数,它接受三个参数、一对迭代器和一个转换值的函数 一个用例可以是从一系列值创建一个集合并进行转换,例如,将C++ 在函数模板中使用lambda,can';t推断类型,makeSet()用例,c++,c++11,templates,lambda,type-deduction,C++,C++11,Templates,Lambda,Type Deduction,我想要实现的是一个makeSet()函数,它接受三个参数、一对迭代器和一个转换值的函数 一个用例可以是从一系列值创建一个集合并进行转换,例如,将std::map转换为std::set. 客户端代码可能看起来像 auto s = makeSet(hash.begin(), hash.end(), [](std::pair<int,int> x) { return std::make_pair(x.second, x.first); }); auto s=makeSet(has
std::map
转换为std::set.
客户端代码可能看起来像
auto s = makeSet(hash.begin(), hash.end(),
[](std::pair<int,int> x) { return std::make_pair(x.second, x.first); });
auto s=makeSet(hash.begin(),hash.end(),
[](std::pair x){返回std::make_pair(x.second,x.first);});
我目前的尝试如下:
// (commented code are some other *failed* attempt).
template <typename Iterator,
typename T = typename std::iterator_traits<Iterator>::value_type,
template<typename ... > class Monad, typename R >
// typename R, typename Monad = std::function<R(T)> >
std::set<R> makeSet(Iterator first, Iterator last, Monad<R,T> f) {
std::set<R> res;
for (; first != last; ++first) res.insert(f(*first));
return res;
}
//(注释的代码是其他一些*失败*的尝试)。
模板
//typename R,typename Monad=std::function>
set makeSet(迭代器优先,迭代器最后,Monad f){
std::set res;
对于(;first!=last;++first)res.insert(f(*first));
返回res;
}
但不幸的是,这不起作用。这个问题似乎无法推导出R
有什么解决方案或解决办法吗?
如果您能告诉我正确的方法,我将不胜感激。lambda表达式的类型是未命名的类类型(其闭包类型),而不是
std::function
。因此,您无法从中推断出std::function
或Monad
您的最佳选择是做标准库所做的事情,并简单地接受任何内容作为谓词:
template <
class Iterator,
class UnaryFunction
>
auto makeSet(Iterator first, Iterator last, UnaryFunction f) -> std::set<decltype(f(*first))>
{
std::set<decltype(f(*first))> res;
for (; first != last; ++first) res.insert(f(*first));
return res;
}
模板<
类迭代器,
类一元函数
>
自动生成集(迭代器优先、迭代器最后、一元函数f)->std::set
{
std::set res;
对于(;first!=last;++first)res.insert(f(*first));
返回res;
}
请注意,您可能必须在std::remove_reference
和/或std::remove_cv
中包装decltype
,以覆盖所有角落的情况(或者按照std::decay
的建议)
此外,为了避免重新发明轮子,你可能想看看图书馆。“你越是过度思考管道,就越容易堵塞排水管。”——斯科蒂,《星际迷航III》
没有必要像那样过度设计模板函数。只需使用转发引用,并让您的C++17编译器解决所有问题
#include <set>
#include <map>
#include <utility>
#include <type_traits>
// (commented code are some other *failed* attempt).
template <typename Iterator, typename Lambda>
auto makeSet(Iterator first, Iterator last, Lambda &&f) {
typedef typename std::remove_reference<decltype(first->first)>::type const_first_t;
typedef typename std::remove_const<const_first_t>::type first_t;
typedef typename std::remove_reference<decltype(first->second)>::type second_t;
typedef std::pair<first_t, second_t> R;
std::set<R> res;
for (; first != last; ++first) res.insert(f(*first));
return res;
}
void foo()
{
std::map<int, int> m;
std::set<std::pair<int, int>> s =
makeSet(m.begin(), m.end(),
[](const auto &x)
{
return std::make_pair(x.second, x.first);
});
}
#包括
#包括
#包括
#包括
//(注释代码是其他一些*失败*的尝试)。
模板
自动生成集(迭代器优先、迭代器最后、Lambda&&f){
typedef typename std::remove_referencefirst)>::type const_first\t;
typedef typename std::remove_const::type first\u t;
typedef typename std::remove_referencesecond)>::键入second\u t;
typedef std::对R;
std::set res;
对于(;first!=last;++first)res.insert(f(*first));
返回res;
}
void foo()
{
std::map m;
std::集s=
makeSet(m.begin(),m.end(),
[](常量自动和x)
{
返回std::make_pair(x.second,x.first);
});
}
R
应该是f(*first)
的衰减类型,而不是你在这里写的任何东西。说得好!虽然我更喜欢更简洁的版本。这就是为什么我不能提出类似的解决方案,它太过大胆地寻找不熟悉的人。正如@Barry指出的,需要更通用的R,尽管想法类似。此外,这个解决方案是否可以适应C++03,-不使用decltype
--而不需要太多麻烦?在C++03中,我看不到任何版本的简单方法。除非在其他模板参数中显式指定所有内容的类型,否则不会。一句话:升级你的编译器:-)哦,亲爱的,有时挑剔的decltype!!range是否意味着使用range对象而不是一对迭代器,类似于或不同的迭代器?我只会使用std::detacient\t
,因为detacient\t
使类型适合存储。第二点是,您几乎不应该推断std::function
的类型std::function
是一个类型擦除类,类型推断和类型擦除是相反的。推断要擦除的类型是设计缺陷的标志。你删除,因为你需要一个固定的类型在这里;你推断是因为你知道这里的确切类型。如果你知道确切的类型,999/1000次你不需要固定的类型。