假设我想要一个普通的高阶函数。最常见的方法是:
A.通用羔羊a
auto F1 = [](auto f) { /*...*/ }B.功能模板
template<class F> auto F2(F&& f) { /*...*/ }我的问题是如何在高阶函数中使用 f。虽然只有一种方法可以防止A:
std::forward<decltype(f)>(f)(...); 案例B至少有两种方法:
std::forward<decltype(f)>(f)(...);
std::forward<F>(f)(...); 这些方法是否等同,如果不是,“断领带”的一些例子是什么?
发布于 2015-10-18 02:37:58
正如所写的,案例A和案例B的声明是不一样的。案例B可以推导出一个lvalue或rvalue引用,但是案例A只能演绎一个值类型。auto类似于模板参数,因此将auto更改为auto&&以使声明匹配。
要回答你的问题,它们是等价的。唯一的区别是引用崩溃发生在B种情况下。当传递给decltype(f)的参数为rvalue时,F始终是引用,而F是值类型:
F2(<lvalue>); decltype(f) == T&, F == T&
F2(<rvalue>); decltype(f) == T&&, F == T这对std::forward并不重要,因为引用折叠总是会产生正确的类型。
template< class T >
constexpr T&& forward( typename std::remove_reference<T>::type& t );如果T是F&&,则返回类型仍然是T&&,因为T&& && == T&&。如果T只是一个F (值类型),那么返回类型仍然是相同的(T && == T&&)。参考折叠规则可在本站上找到。
TLDR:没有有效的区别,因为引用折叠会产生相同的类型。
发布于 2015-10-18 02:39:53
当您使用不同类型的参数( rvalue引用、const lvalue引用和non引用)调用您的F2时,让我们来看看正在发生的事情。让我们不要讨论volatile,因为它基本上不添加任何新信息(它的行为与const或const volatile一样),并假设您为了简单起见传递了不同的int。
首先,推导出F的类型:
int&&,F将是int,但是(decltype(f) == int&&)。const int&,F将是const int& (decltype(f) == const int&)int&,F将是int& (decltype(f) == int&)因此,您可以看到,对于后两种情况,decltype(f) == F,所以没有什么需要进一步分析的。但是,对于第一种情况,它们是不同的,因此让我们更深入地研究这一点。
然后将F或decltype(f)作为模板参数传递给std::forward。std::forward 收纳 a std::remove_reference<T>&或std::remove_reference<T>&&,因此参数类型在这两种情况下都是相同的。但是,返回类型可能是不同的(因为我们为它传递不同的T -- int和int&&)。但是,由于编译器执行的引用折叠(同样,请参阅Scott对细节的解释),int&& &&变成了简单的int&&。因此返回值也是相同的。
总之,如果您将decltype(f)或F用于std::forward,则没有区别。
另外,这里有一些活着示例,它显示了所有推导的类型,甚至对于像const volatile int &&这样的无用的(但有效的)野兽也是如此。
https://stackoverflow.com/questions/33193254
复制相似问题