问题描述
请考虑以下代码,这些代码是受Barry对问题的回答的启发:
Consider the following code, inspired from Barry's answer to this question:
// Include
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
// Generic overload rank
template <std::size_t N>
struct overload_rank
: overload_rank<N - 1>
{
};
// Default overload rank
template <>
struct overload_rank<0>
{
};
// Prepend argument to function
template <std::size_t N, class F>
auto prepend_overload_rank(F&& f) {
using rank = overload_rank<N>;
return [f = std::forward<F>(f)](rank, auto&&... args) -> decltype(auto) {
return std::forward<F>(f)(std::forward<decltype(args)>(args)...); // here
};
}
// Main
int main(int argc, char* argv[])
{
auto f = [](int i){return i;};
prepend_overload_rank<5>(f)(overload_rank<5>(), 1);
return 0;
}
由于在此处<
,我不明白为什么:
It is not compiling because of line noted here
, and I don't understand why:
With g++:
error: no matching function for call to 'forward<main(int, char**)::<lambda(int)>&>(const main(int, char**)::<lambda(int)>&)'
With clang:
error: no matching function for call to 'forward'
替换
return std::forward<F>(f)(std::forward<decltype(args)>(args)...);
by
return f(std::forward<decltype(args)>(args)...);
显然可以使它工作,但是同样,我也不明白为什么,我的目标是实现
apparently makes it work, but again, I don't understand why, and my goal is to achieve a perfect forwarding of the function.
推荐答案
显然,编译器已被调试或允许将被复制捕获的变量声明为 const
当 mutable
说明符不存在时。
具有讽刺意味的是,以下代码使用GCC进行编译,但不会编译t与clang:
Apparently compilers are either bugged or allowed to declare variables captured by copy as const
when the mutable
specifier is not present.
Ironically, the following compiles with GCC, but it doesn't with clang:
#include <type_traits>
int main(int argc, char* argv[]) {
int i = 0;
[j = i](){ static_assert(std::is_same<decltype(j), const int>::value, "!"); }();
}
要在两种情况下都解决此问题,您可以执行以下操作:
To work around the issue in both cases you can do this:
return [f = std::forward<F>(f)](auto&&... args) -> decltype(auto) {
return std::forward<decltype(f)>(f)(std::forward<decltype(args)>(args)...); // here
};
也就是说,您可以省略变量
关键字,但您必须在lambda中使用 f
副本的实际类型。请注意,原始 f
是对lambda函数的非常量引用,因此 F
可以不同于lambda中的类型 decltype(f)
。
在任何情况下都有效,即使对于 mutable
lambda。例如:
That is, you can omit the mutable
keyword, but you have to use the actual type of the copy of f
within the lambda. Note that the original f
is a non-const reference to a lambda function, thus F
can differ from the type decltype(f)
within the lambda.
This is valid in any case, even for mutable
lambda. As an example:
#include <type_traits>
#include<utility>
struct S {};
template<typename T>
void f(T &&t) {
[t = std::forward<T>(t)]()mutable{ static_assert(std::is_same<decltype(t), S>::value, "!"); }();
// the following doesn't compile for T is S& that isn't the type of t within the lambda
//[t = std::forward<T>(t)]()mutable{ static_assert(std::is_same<decltype(t), T>::value, "!"); }();
}
int main() {
S s;
f(s);
}
通常,应使用捕获变量的实际类型而不是
在特定情况下,即使编译器错误地将捕获的变量声明为 const
,您也可以使其工作而无需只要 f
的函数运算符为 const $ c $,
可变
说明符c>(这就是您的情况,因为 f
是 main
不是可变
)。
In general, you should use the actual type of the captured variable instead of the type given in a surrounding context.
In the specific case, even though the compiler wrongly declares the captured variable as const
, you can make it work without the mutable
specifier as long as the function operator of f
is const
(that is your case, for f
is main
isn't mutable
as well).
让摘要运行的另一种方法是(如对问题的评论中所建议的):
Another way to let your snippet work is this (as suggested in the comments to the question):
return [f = std::forward<F>(f)](auto&&... args) mutable -> decltype(auto) {
return std::forward<F>(f)(std::forward<decltype(args)>(args)...); // here
};
在这种情况下,不能将复制捕获的变量强制为 const
并且类型是预期的类型。
无论如何,即使您打算使用 mutable $,我还是建议您采纳上述建议。 c $ c>说明符。
In this case, variables captured by copy cannot be forced to be const
and the type is the expected one.
Anyway, I'd suggest to take the advice above even if you are planning to use the mutable
specifier.
注意。
如出现此问题是由于海湾合作委员会。使用 decltype(f)
的建议仍然有效。它也解决其他类型的问题,并适用于特定情况。而且,如果错误已修复,代码将继续正常运行。
Note.
As discussed in this question the problem arose because of a bug of GCC. The suggestion to use decltype(f)
still stands. It addresses also other types of problems and works for the specific case. Moreover, in case the bug is fixed, the code will continue to work properly.
这篇关于没有匹配函数std :: forward与lambdas的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!