Nik*_*mel 5 c++ lambda variadic-templates perfect-forwarding
这是关于lambda重载集和完美转发的问题,并且是评论的后续内容。有关如何使用它的更多上下文,请参阅另一个相关问题。
我对以下代码段有一些疑问。
Q1:对于拉姆达过载,我用的是overload(Fs...) -> overload<Fs...>从这个帖子,但随后这个答案我看到了overload(Fs&&...) -> overload<std::decay_t<Fs>...>。这种差异在什么情况下有意义?
问题2:为什么要identity使用return decltype(x)(x)而不是仅定义以下函数return x?
问题3:我们可以foo(convert(std::forward<Args>(args))...)像对待所有未转换的参数一样,将其视为完美的转发foo(std::forward<Args>(args)...)吗?
#include <utility>
#include <iostream>
/////////////////////////////////////////////////////////////////////////////////
struct Foo {
virtual ~Foo() = default;
};
struct FooA: public Foo {
static void foo(const FooA&, int) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
struct FooB: public Foo {
static void foo(int, const FooB&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
/////////////////////////////////////////////////////////////////////////////////
template<class...Fs>
struct overload:Fs... {
using Fs::operator()...;
};
// Q1: In what situations is needed over `overload(Fs...) -> overload<Fs...>`?
template<class...Fs>
overload(Fs&&...) -> overload<std::decay_t<Fs>...>;
/////////////////////////////////////////////////////////////////////////////////
// Q2: What is the purpose of `return decltype(x)(x)` over `return x`?
auto identity=[](auto&&x)->decltype(x){return decltype(x)(x);};
template<typename SpecificFoo, typename... Args>
void bar(Args&&... args) {
auto convert = overload{
[](const Foo& f){return dynamic_cast<const SpecificFoo&>(f);},
identity
};
// Q3: Is our definition of `convert` "perfectly forwarding", like if we just called
// `foo(std::forward<Args>(args)...)`, or in what situations might this not do the
// same thing (for not-converted types)?
SpecificFoo::foo(convert(std::forward<Args>(args))...);
}
/////////////////////////////////////////////////////////////////////////////////
int main() {
{
FooA specific_foo;
const Foo& foo {specific_foo};
// assume we only have access to foo when calling bar
bar<FooA>(foo, 23);
}
{
FooB specific_foo;
const Foo& foo {specific_foo};
// assume we only have access to foo when calling bar
bar<FooB>(42, foo);
}
}
Run Code Online (Sandbox Code Playgroud)
这种差异在什么情况下相关?
当至少一个参数实际上是左值时(identity事实上,像 )。在这种情况下,对应的Fi是 a T&,即左值引用。并且不能将左值引用列为任何类的基类,因此std::decay需要删除所有引用和 cv 限定符。当演绎指南按值获取参数时,它自动就不是问题了。这是因为值类型的模板参数推导已经“衰减”了类型。
如果您想知道该使用哪一个,那么我会说客观上杂乱较少的更好。使用std::decay_t是为了获得与按值版本相同的行为,因此也可以使用它。
为什么你想要定义下面的恒等函数 return decltype(x)(x) 而不仅仅是 return x
这是一种转发形式。由于 lambda 的返回类型被声明为decltype(x),因此我们需要进行强制转换以确保它正确绑定到右值引用。因为在这种情况下decltype(x) = T&&,它不会绑定到xalone,这是一个左值。
我们可以认为
foo(convert(std::forward<Args>(args))...)完美转发(对于所有未转换的参数)就像foo(std::forward<Args>(args)...)
是的。参数bar已经绑定到引用。convert让这些引用通过并保留值类别,因此它确实在转发。