带有lambda的std :: function返回类型的模板自变量类型推导 [英] template argument type deduction from std::function return type with lambda

查看:83
本文介绍了带有lambda的std :: function返回类型的模板自变量类型推导的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我正在使用C ++ 11(并且我的主题很烂)。

First of, I'm using C++11 (and my topic sucks).

我要写的是编写一个通用模板函数,在其他编程语言中实现通常称为 sort_by 的东西。它涉及为范围的每个成员精确计算一次任意准则,然后根据这些准则对该范围进行排序。这样的标准不一定非要是POD,它所必须具备的功能远非可比。对于 std :: less 不起作用的事情,调用者应该能够提供自己的比较函子。

What I'm trying to do is write a generic template function that implements something usually called sort_by in other programming languages. It involves calculating an arbitrary criterion for each member of a range exactly once and then sorting that range according to those criteria. Such a criterion doesn't have to be a POD, all it has to be is less-than-comparable. For things for which std::less doesn't work the caller should be able to provide her own comparison functor.

我已经成功编写了使用以下签名的函数:

I've successfully written said function which uses the following signature:

template<  typename Tcriterion
         , typename Titer
         , typename Tcompare = std::less<Tcriterion>
         >
void
sort_by(Titer first, Titer last,
        std::function<Tcriterion(typename std::iterator_traits<Titer>::value_type const &)> criterion_maker,
        Tcompare comparator = Tcompare()) {
}

例如像这样:

struct S { int a; std::string b; double c; };
std::vector<S> s_vec{
  { 42, "hello", 0.5 },
  { 42, "moo!",  1.2 },
  { 23, "fubar", 0.2 },
};

sort_by1< std::pair<int, double> >(
  s_vec.begin(), s_vec.end(),
  [](S const &one_s) { return std::make_pair(one_s.a, one_s.c); }
);

我不喜欢这种方法,因为我必须提供 Tcriterion 我自己是因为编译器无法从lambda表达式中推断出该类型。因此,这不起作用:

What I don't like about this approach is that I have to provide the Tcriterion argument myself because the compiler cannot deduce that type from the lambda expression. Therefore this does not work:

sort_by1(s_vec.begin(), s_vec.end(), [](S const &one_s) { return std::make_pair(one_s.a, one_s.c); });

clang 3.1和gcc 4.7.1都对此表示反对(gcc 4.7.1甚至在上面的代码中吠叫,所以我想我在这里确实做错了。)

clang 3.1 and gcc 4.7.1 both bark on this (gcc 4.7.1 even barks on the code above, so I guess I'm really doing something wrong here).

但是,如果我先将lambda分配给 std :: function ,那么至少clang 3.1可以推论该参数,这意味着有效:

However, if I assign the lambda to a std::function first then at least clang 3.1 can deduce the argument, meaning this works:

typedef std::pair<int, double> criterion_type;
std::function<criterion_type(S const &)> criterion_maker = [](S const &one_s) {
  return std::make_pair(one_s.a, one_s.c);
};
sort_by1(s_vec.begin(), s_vec.end(), criterion_maker);

所以我的问题是:我如何更改我的函数签名,这样我才不需要指定一个参数?并且(可能相关)我如何解决我的示例以使其与gcc一起使用?

So my questions are: How do I have to change my function signature so that I don't need to specify that one argument? And (probably related) how would I fix my example to have it working with gcc?

推荐答案

不要使用 std :: function 与模板参数推导配合使用。实际上,几乎没有理由在函数或函数模板参数列表中使用 std :: function 。通常,您不应该使用 std :: function ;它是一种非常专业的工具,非常擅长解决一个特定问题。其余时间,您可以完全省去它。

Don't use std::function in tandem with template argument deduction. In fact, there's very likely no reason to use std::function in a function or function template argument list. More often than not, you should not use std::function; it is a very specialized tool that is very good at solving one particular problem. The rest of the time, you can dispense with it altogether.

如果您使用多态函子对事物进行排序,则不需要模板参数推导:

In your case you don't need template argument deduction if you use a polymorphic functor to order things:

struct less {
    template<typename T, typename U>
    auto operator()(T&& t, U&& u) const
    -> decltype( std::declval<T>() < std::declval<U>() )
    { return std::forward<T>(t) < std::forward<U>(u); }

    // operator< is not appropriate for pointers however
    // the Standard defines a 'composite pointer type' that
    // would be very helpful here, left as an exercise to implement
    template<typename T, typename U>
    bool operator()(T* t, U* u) const
    { return std::less<typename std::common_type<T*, U*>::type> {}(t, u); }
};

然后可以声明:

template<typename Iter, typename Criterion, typename Comparator = less>
void sort_by(Iter first, Iter last, Criterion crit, Comparator comp = less {});

comp(* ita,* itb)会做正确的事情,以及 comp(crit(* ita),crit(* itb))或其他任何可以做的事情。

and comp(*ita, *itb) will do the right thing, as well as comp(crit(*ita), crit(*itb)) or anything else as long as it makes sense.

这篇关于带有lambda的std :: function返回类型的模板自变量类型推导的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆