Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在函数模板中使用lambda,can';t推断类型,makeSet()用例_C++_C++11_Templates_Lambda_Type Deduction - Fatal编程技术网

C++ 在函数模板中使用lambda,can';t推断类型,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

我想要实现的是一个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(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次你不需要固定的类型。