使用std::function
,我们可以使用argument_type
,second_argument_type
等typedef来获取参数的类型,但我看不到用lambdas做同样事情的方法。可能吗? (我正在使用VS2010)
我想在我的反序列化系统中使用以下内容来读取对象并将其传递给setter函数:
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);
}
它可以像这样使用,一切正常:
std::function<void(int)> f = [](int i) -> void { setValue(i); };
forward(f);
但它不会直接与lambdas一起使用:
forward([](int i) -> void { setValue(i); });
//error C2039: 'argument_type' : is not a
//member of '`anonymous-namespace'::<lambda1>'
有没有办法以一种适用于lambdas和std::function
对象的方式访问参数类型?也许首先获得lambda的std::function
类型,然后再获取argument_type
?
根据以下答案,使用lambdas和std::function
的版本是:
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); });
由于int
在这里重复,我希望摆脱它 - 对于int
来说并不是那么糟糕,但对于几个命名空间中的长命名类型更令人讨厌。 C'est la vie!
答案 0 :(得分:20)
在一般情况下,这是不可取的。 (请注意,std::function<T(A)>
很容易指定例如argument_type
的内容:它只是A
!它在类型定义中可用。)
可以要求每个函数对象类型指定其参数类型,并依次强制从lambda表达式生成的闭包类型这样做。事实上,像适应性仿函数这样的前C ++ 0x特性只适用于这种类型。
然而,我们正在使用C ++ 0x,并且有充分的理由。最简单的就是简单重载:带有模板operator()
(a.k.a是一个多态函数)的仿函数类型只需要所有类型的参数;那么argument_type
应该是什么?另一个原因是通用代码(通常)试图指定对其操作的类型和对象的最小约束,以便更容易(重新)使用。
换句话说,对于Functor f
,typename Functor::argument
为int
,通用代码确实感兴趣。知道f(0)
是一个可以接受的表达式,这是更多有趣。对于这个C ++ 0x,提供decltype
和std::declval
等工具(方便地将两个包装在std::result_of
内)。
我看到它的方式有两个选择:要求传递给模板的所有仿函数都使用C ++ 03式约定argument_type
等等;使用下面的技术;或重新设计。我推荐最后一个选项,但这是你的电话,因为我不知道你的代码库是什么样的,或者你的要求是什么。
对于单形仿函数类型(即没有过载),可以检查operator()
成员。这适用于lambda表达式的闭包类型。
所以我们声明这些助手
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)
接受指向至少一个参数的成员函数的指针。现在:
template<typename F>
struct first_argument {
typedef decltype( helper(&F::operator()) ) type;
};
[一个精心设计的特征可以连续查询lvalue-rvalue / const / volatile重载并公开第一个参数,如果它对所有重载都相同,或者使用std::common_type
。]
答案 1 :(得分:5)
@Luc的答案很棒,但我遇到了一个案例,我还需要处理函数指针:
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
这可以在函子和函数指针上使用:
void function(float);
struct functor {
void operator() (int);
};
int main() {
std::cout << std::is_same<first_argument<functor>, int>::value
<< ", "
<< std::is_same<first_argument<decltype(&function)>, int>::value
<< std::endl;
return 0;
}