在函数模板中使用lambda,无法推断类型,makeSet()用例

use lambda in function template, can't deduce type, makeSet() use case

本文关键字:类型 makeSet 用例 函数模板 lambda      更新时间:2023-10-16

我想实现的是一个akeet()函数,接受三个参数,一对迭代器和一个转换值的函数。

一种用例可能是从一系列值创建一个集合,并进行转换,例如,将std::map<K,V>转换为std::set<std::pair<V,K>>.

客户端代码看起来像

auto s = makeSet(hash.begin(), hash.end(),
    [](std::pair<int,int> x) { return 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;
}

,但不幸的是不起作用。这个问题似乎无法推断出R。

有任何解决方案或解决方法吗?如果您能告诉我正确的方法,我将非常感谢。

lambda表达式的类型是未命名的类型(其闭合类型),而不是std::function。因此,您不能从中推导std::functionMonad

您最好的选择是做标准库的所作所为,只是接受任何东西作为谓词:

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

请注意,您可能必须将decltype包装在std::remove_reference和/或std::remove_cv中才能覆盖所有角色案例(或,如@yakk,std::decay)。

另外,为了避免重新发明轮子,您可能需要查看boost.range库。

"您越多地思考管道,就越容易停止排水管。" - 斯科蒂,星际迷航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);
            });
}