关于 lambda 重载、类型转换和完美转发的问题
Questions on lambda overloads, type conversions and perfect forwarding
这是一个关于 lambda 重载集和完美转发的问题,是 . For more context of how this is used see .
的后续问题
我对下面的代码片段有一些疑问。
Q1:对于 lambda 重载,我使用 this post, but then in 中的 overload(Fs...) -> overload<Fs...>
我看到 overload(Fs&&...) -> overload<std::decay_t<Fs>...>
。这种差异在什么情况下相关?
问题 2:为什么要用 return decltype(x)(x)
而不仅仅是 return x
来定义下面的 identity
函数?
Q3:我们是否可以将 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);
}
}
In what situations is this difference relevant?
当至少一个参数实际上是一个左值时(实际上像 identity
)。在这种情况下,相应的 Fi
是 T&
,即左值引用。并且不能将左值引用列为任何 class 的基础,因此需要 std::decay
来删除所有引用和 cv 限定符。当演绎指南按值获取参数时,它自动就不是问题了。这是因为值类型的模板参数推导已经 "decays" 类型。
如果您想知道该使用哪一个,那么客观上我会说混乱较少的那个更好。使用 std::decay_t
是为了获得与按值版本相同的行为,因此也可以使用它。
Why would you want to define the identity function below with return decltype(x)(x) and not just return x
这是一种转发形式。由于 lambda 的 return 类型声明为 decltype(x)
,我们需要强制转换以确保它正确绑定到右值引用。因为在 decltype(x) = T&&
的情况下,它不会单独绑定到 x
,这是一个左值。
Can we consider foo(convert(std::forward<Args>(args))...)
as perfect forwarding (for all not-converted arguments) just like foo(std::forward<Args>(args)...)
是的。 bar
的参数已经绑定到引用。 convert
让那些引用通过并保留值类别,所以它确实在转发。
这是一个关于 lambda 重载集和完美转发的问题,是
我对下面的代码片段有一些疑问。
Q1:对于 lambda 重载,我使用 this post, but then in overload(Fs...) -> overload<Fs...>
我看到 overload(Fs&&...) -> overload<std::decay_t<Fs>...>
。这种差异在什么情况下相关?
问题 2:为什么要用 return decltype(x)(x)
而不仅仅是 return x
来定义下面的 identity
函数?
Q3:我们是否可以将 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);
}
}
In what situations is this difference relevant?
当至少一个参数实际上是一个左值时(实际上像 identity
)。在这种情况下,相应的 Fi
是 T&
,即左值引用。并且不能将左值引用列为任何 class 的基础,因此需要 std::decay
来删除所有引用和 cv 限定符。当演绎指南按值获取参数时,它自动就不是问题了。这是因为值类型的模板参数推导已经 "decays" 类型。
如果您想知道该使用哪一个,那么客观上我会说混乱较少的那个更好。使用 std::decay_t
是为了获得与按值版本相同的行为,因此也可以使用它。
Why would you want to define the identity function below with return decltype(x)(x) and not just return x
这是一种转发形式。由于 lambda 的 return 类型声明为 decltype(x)
,我们需要强制转换以确保它正确绑定到右值引用。因为在 decltype(x) = T&&
的情况下,它不会单独绑定到 x
,这是一个左值。
Can we consider
foo(convert(std::forward<Args>(args))...)
as perfect forwarding (for all not-converted arguments) just likefoo(std::forward<Args>(args)...)
是的。 bar
的参数已经绑定到引用。 convert
让那些引用通过并保留值类别,所以它确实在转发。