[英]How to make template deduce return type of function with variadic arguments
Someone on stack overflow wrote an interesting way to capture a lambda or functor into your own class. 堆栈溢出的人写了一个有趣的方法来将lambda或functor捕获到你自己的类中。 I was trying to simplify it, and I think I got close but was having some trouble. 我试图简化它,我认为我很接近,但遇到了一些麻烦。 Their example was: 他们的例子是:
// OT => Object Type
// RT => Return Type
// A ... => Arguments
template<typename OT, typename RT, typename ... A>
struct lambda_expression {
OT _object;
RT(OT::*_function)(A...)const; // A pointer to a member function,
// specifically the operator()
lambda_expression(const OT & object) // Constructor
: _object(object),
_function(&decltype(_object)::operator()) {} // Assigning the function pointer
RT operator() (A ... args) const {
return (_object.*_function)(args...);
}
};
Basically this allows you to go: 基本上这可以让你去:
int captureMe = 2;
auto lambda = [=](int a, int b) { return a + b + captureMe;};
lambda_expression<decltype(lambda), int, int, int>(lambda);
I was trying to simplify this, and thought that the pointer contained in the lambda_expression class wouldn't be needed, because you can call the function object itself, instead of calling the pointer to the operator(). 我试图简化这一点,并认为不需要lambda_expression类中包含的指针,因为你可以调用函数对象本身,而不是调用指向operator()的指针。 So I tried this: 所以我尝试了这个:
template <typename OT, typename ... Args> // No Return type specified
struct lambdaContainer
{
lambdaContainer(OT funcObj) : funcObj(funcObj){ }
OT funcObj; // No pointer, just the function object.
auto operator()(Args... args)
{
return funcObj(args...); // Call the function object directly
}
};
Then something like: 然后像:
int captureMe = 2;
auto lambda = [=](int a, int b) { return a + b + captureMe; };
lambdaContainer<decltype(lambda), int, int> lam(lambda);
auto i = lam(1, 1);
// i = 4;
Where I wrote the line: 我写的那条线:
auto operator()(Args... args)
{
return funcObj(args...);
}
Apparently: 显然:
decltype(auto) operator()(Args... args) //works in C++14 apparently.
But I tried without the auto keyword and I failed miserably in doing this, I want to understand how the Args... works. 但我试过没有auto关键字,我在这方面做得很糟糕,我想了解Args是如何工作的。 I tried: 我试过了:
decltype(funObj(Args...) operator()(Args... args) // this failed
decltype(OT(Args...) operator() (Args... args) // this failed
auto operator() (Args... args) -> decltype(funcObj(Args...)) // this failed
auto operator() (Args... args) -> decltype(OT(Args...)) // this failed
How can I expand the Args parameter so the template can deduce the return type? 如何扩展Args参数,以便模板可以推导出返回类型? Is this only possible with auto? 这只能用汽车吗?
decltype(e)
takes an expression e
and evaluates to the type of that expression . decltype(e)
接受表达式 e
并计算该表达式的类型。 You need to provide an expression that represents the invocation of your stored lambda: 您需要提供一个表达式来表示存储的lambda的调用:
auto operator()(Args... args)
-> decltype(std::declval<OT>()(std::declval<Args>()...))
In this case, I'm using std::declval
to create a "fake instance" of the objects that can be used for deduction purposes, without actually invoking any constructor. 在这种情况下,我使用std::declval
来创建可用于演绎目的的对象的“伪实例”,而不实际调用任何构造函数。
Let's break this down even further: 让我们进一步打破这个:
-> decltype(
std::declval<OT>() // create a fake instance of `OT`
( // invoke it
std::declval<Args>()... // create a fake instance of each argument
// type, expanding `Args...`
)
)
live example on wandbox wandbox上的实例
By the way, you should still std::forward
the arguments in your call to funcObj
as there might be some rvalue references that need to be propagated further down: 顺便说一下,你仍然应该在调用funcObj
std::forward
参数,因为可能有一些rvalue引用需要进一步向下传播:
auto operator()(Args... args)
{
return funcObj(std::forward<Args>(args)...);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.