我们可以得到lambda参数的类型吗? [英] Can we get the type of a lambda argument?

查看:104
本文介绍了我们可以得到lambda参数的类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 std :: function ,我们可以使用 argument_type second_argument_type 等typedefs,但我看不到一个方法做同样的事情与lambdas。是否可以? (我正在使用VS2010)



说我想在反序列化系统中使用下面的东西来读取一个对象,并将它传递给setter函数:

  template< typename F> 
static void forward(F f)
{
//创建一个第一个类型的对象
//到函数对象的参数F
typedef typename F :: argument_type T;
T t;

//...do用't'在这里(在我的情况下deserialize)

//将对象转发到函数
f(t);
}

它可以像这样使用,一切正常:

  std :: function< void(int)> f = [](int i) - > void {setValue(i) }; 
forward(f);

但它不能直接与lambdas一起使用:

  forward([](int i) - > void {setValue(i);}); 
//错误C2039:'argument_type':不是
//'anonymous-namespace'的成员::< lambda1>'
pre>

有一种方法可以访问参数类型的方式,将同时适用于lambdas和 std :: function 对象?也许一种方法先得到 std :: function 类型的lambda,然后从 argument_type / p>




从下面的答案可以看出,使用lambdas和 std :: function 是:

  template< typename T,typename F& 
static void forward(F f)
{
T t;

//...do do't'here(deserialize in my case)

f(t);
}

forward< int>([](int i) - > void {setValue(i);});

因为 int 去除它 - 对于 int 不是那么坏,但更令人烦恼的长命名类型在几个命名空间。

解决方案

这在一般情况下是不可取的。 (注意, std :: function< T(A)> 很容易指定例如 argument_type A !它在类型定义中可用。)



函数对象类型来指定其参数类型,反过来授权从lambda表达式生成的闭包类型。事实上,pre-C ++ 0x功能像适应性函子只适用于这种类型。



但是,我们正从C ++ 0x和好理由。最简单的是简单的重载:一个带有模板的运算符()(a.k.a一个多态函子)的函子类型只需要所有类型的参数;所以应该 argument_type 是什么?另一个原因是泛型代码(通常)尝试指定对其操作的类型和对象的最小约束,以便更容易地(重新)使用。



换句话说,泛型代码不是真的感兴趣的给定 Functor f typename Functor :: argument be int 。更多有趣的是, f(0)是一个可接受的表达式。对于这个C ++ 0x给出了工具,如 decltype std :: declval c $ c> std :: result_of )。



我看到它的方式有两个选择:要求传递给你的模板使用指定 argument_type 等的C ++ 03风格约定;使用下面的技术;或重新设计。我建议最后一个选项,但它是你的电话,因为我不知道你的代码库或你的要求是什么。






对于单态函子类型(即没有重载),可以检查 operator()成员。



所以我们声明这些辅助函数。

  template< typename F,typename Ret,typename A,typename ... Rest> 
A
helper(Ret(F :: *)(A,Rest ...));

template< typename F,typename Ret,typename A,typename ... Rest>
A
helper(Ret(F :: *)(A,Rest ...)const);

// volatile或lvalue / rvalue *对于lambdas(phew)不是必需的

接受指向至少一个参数的成员函数的指针。现在:

 模板< typename F> 
struct first_argument {
typedef decltype(helper(& F :: operator()))type;
};

[精心设计的trait可以连续查询lvalue-rvalue / const / volatile重载并公开第一个参数如果对于所有重载都是相同的,或者使用 std :: common_type 。作为练习留给读者。 ]


Using std::function, we can get the type of an argument using the argument_type, second_argument_type etc. typedefs, but I can't see a way to do the same thing with lambdas. Is it possible? (I'm using VS2010)

Say I want something like the following in my deserialization system used to read an object and pass it to a setter function:

template<typename F> 
static void forward(F f)
{ 
    // Create an object of the type of the first
    // parameter to the function object F
    typedef typename F::argument_type T;
    T t;

    //...do something with 't' here (deserialize in my case)

    // Forward the object to the function
    f(t);
}

It can be used like this and everything works fine:

std::function<void(int)> f = [](int i) -> void { setValue(i); };
forward(f);

But it will not work directly with lambdas:

forward([](int i) -> void { setValue(i); });
//error C2039: 'argument_type' : is not a 
//member of '`anonymous-namespace'::<lambda1>'

Is there a way to access the parameter types in a way that will work for both lambdas and std::function objects? Maybe a way to get the std::function type of a lambda first, and then the argument_type from that?


Following on from the answer below, a version that works with lambdas and std::function is:

template<typename T, typename F> 
static void forward(F f)
{ 
    T t;

    //...do something with 't' here (deserialize in my case)

    f(t);
}

forward<int>([](int i) -> void { setValue(i); });

Since int is repeated here I was hoping to get rid of it - not so bad for int but more annoying for long-named types in a couple of namespaces. C'est la vie!

解决方案

It's not desirable in the general case. (Note that it's quite easy for std::function<T(A)> to specify what e.g. argument_type is: it's just A! It's available in the type definition.)

It would be possible to require each and every function object type to specify its argument types, and in turn mandate that the closure types generated from lambda expression do so. In fact, pre-C++0x features like adaptable functors would only work for such types.

However, we're moving from that with C++0x and for good reasons. The simplest of which is simply overloading: a functor type with a templated operator() (a.k.a a polymorphic functor) simply takes all kind of arguments; so what should argument_type be? Another reason is that generic code (usually) attempts to specify the least constraints on the types and objects it operates on in order to more easily be (re)used.

In other words, generic code is not really interested that given Functor f, typename Functor::argument be int. It's much more interesting to know that f(0) is an acceptable expression. For this C++0x gives tools such as decltype and std::declval (conveniently packaging the two inside std::result_of).

The way I see it you have two choices: require that all functors passed to your template use a C++03-style convention of specifying an argument_type and the like; use the technique below; or redesign. I'd recommend the last option but it's your call since I don't know what your codebase looks like or what your requirements are.


For a monomorphic functor type (i.e. no overloading), it is possible to inspect the operator() member. This works for the closure types of lambda expressions.

So we declare these helpers

template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...));

template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...) const);

// volatile or lvalue/rvalue *this not required for lambdas (phew)

that accept a pointer to member function taking at least one argument. And now:

template<typename F>
struct first_argument {
    typedef decltype( helper(&F::operator()) ) type;
};

[ an elaborate trait could successively query the lvalue-rvalue/const/volatile overloads and expose the first argument if it's the same for all overloads, or use std::common_type. left as an exercise to the reader. ]

这篇关于我们可以得到lambda参数的类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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