【发布时间】:2019-03-10 12:46:06
【问题描述】:
这是一个关于 lambda 重载集和完美转发的问题,也是comment 的后续问题。有关如何使用它的更多上下文,请参阅another related question。
我对下面的代码 sn-p 有一些疑问。
Q1:对于 lambda 重载,我使用的是来自 this post 的 overload(Fs...) -> overload<Fs...>,但后来在 this answer 中我看到了 overload(Fs&&...) -> overload<std::decay_t<Fs>...>。这种差异在什么情况下是相关的?
Q2:为什么要在下面用return decltype(x)(x) 定义identity 函数,而不仅仅是return x?
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);
}
}
【问题讨论】:
-
这些都是单独的好问题,但我没有足够的知识来说明是否有一个优雅的统一答案可以一次性应用于所有三个问题。
-
@StoryTeller 我已经考虑过这一点,但我认为这些问题密切相关。只是我指定了我不理解的位,而不是仅仅说“整个事情是如何工作的”?要了解
convert(...)w.r.t 参数转发的行为,我们需要了解identity的行为方式,虽然overload的情况确实略有不同,但它也与它如何处理它的参数有关。 (所以是的,Q1 可能应该是分开的,但恕我直言,Q2 和 Q3 肯定不是......)。 -
嗯...看起来@StoryTeller 删除了他原来的评论,说这个问题可能太宽泛了。无论如何,它现在已经回答了(谢谢!),下次我会更仔细地考虑范围。
标签: c++ lambda variadic-templates perfect-forwarding