C++ 11(和C++ 14)引入了针对通用编程的其他语言结构和改进.这些功能包括:
我在浏览较早草案的的C++ 14规范(现在更新文本)和码中的示例中§20.5.1,编译时整数序列,我发现有趣和奇特.
template<class F, class Tuple, std::size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
using Indices = make_index_sequence<std::tuple_size<Tuple>::value>;
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices());
}
Run Code Online (Sandbox Code Playgroud)
在线这里[intseq.general]/2.
题
f在apply_impl被转发,即为什么std::forward<F>(f)(std::get...?f(std::get...?当我参加C++标准委员会会议时,他们正在讨论删除继承构造函数的优缺点,因为还没有编译器供应商实现它(用户没有要求它的意义).
让我快速提醒大家继承构造函数是什么:
struct B
{
B(int);
};
struct D : B
{
using B::B;
};
Run Code Online (Sandbox Code Playgroud)
一些供应商提出使用r值引用和可变参数模板(完美转发构造函数),在继承类中提供可以避免继承构造函数的转发构造函数是微不足道的.
例如:
struct D : B
{
template<class ... Args>
D(Args&& ... args) : B(args...) { }
};
Run Code Online (Sandbox Code Playgroud)
我有两个问题:
1)您能否从编程经验中提供真实世界(非人为的)示例,这些示例将从继承构造函数中获益匪浅?
2)您是否有任何技术原因可以将"完美的转发建设者"排除在适当的替代方案之外?
谢谢!
我正在编写从其他库中包含很多功能和方法的库.为了避免复制返回值我正在这样应用std::forward:
template<class T>
T&& wrapper(T&& t) {
f(t); // t passed as lvalue
return std::forward<T>(t);
}
Run Code Online (Sandbox Code Playgroud)
f返回void并获取T&&(或超载值).包装器总是返回包装器的参数,返回值应该保留参数的值.我是不是真的需要使用std::forward的return?RVO会让它变得多余吗?它是参考(R或L)的事实是否是多余的?如果return不是最后一个函数语句(在some if中),是否需要它?
如果wrapper()应该返回void或者是有争议的T&&,因为调用者可以通过arg访问评估值(参考,R或L).但在我的情况下,我需要返回值,以便wrapper()可以在表达式中使用.
它可能与这个问题无关,但众所周知,函数f不会被窃取t,所以第一次使用std::forwardin f(std::forward<T>(t))是多余的,它被我删除了.
我写过小测试:https://gist.github.com/3910503
测试显示,返回未转发T- 确实在gcc48和clang32中创建了额外的副本与-O3(RVO没有启动).
此外,我无法从UB中获得不良行为:
auto&& tmp = wrapper(42);
Run Code Online (Sandbox Code Playgroud)
它没有证明任何原因,因为它是未定义的行为(如果它是UB).
C++ 14支持通用lambda.但是,clang 3.4拒绝以下代码.
#include <utility>
void f(int);
void f(int&);
int main()
{
[](auto&& v) { f(std::forward<auto>(v)); }(8); // error
}
Run Code Online (Sandbox Code Playgroud)
如何auto&&在一般的lambda中完美前进?
Scott Meyers在他的新书"Effective Modern C++"中将以下函数显示为使用示例decltype(auto)(第28页):
template<typename Container, typename Index>
decltype(auto)
authAndAccess(Container&& c, Index i)
{
authenticateUser();
return std::forward<Container>(c)[i];
}
Run Code Online (Sandbox Code Playgroud)
我的问题很简单.为什么我们需要std::forward在c这里申请?我们没有经过c任何地方,我们正在呼吁operator[]它.并且没有一个标准容器具有ref-qualified重载(r值/ l值重载)operator[].
所以我认为只有两个原因std::forward:
operator[].std::forward它.期.还有其他原因吗?
我无法弄清楚为什么在最后一种情况下启用了复制省略时调用的移动构造函数(甚至是强制性的,例如在C++ 17中):
class X {
public:
X(int i) { std::clog << "converting\n"; }
X(const X &) { std::clog << "copy\n"; }
X(X &&) { std::clog << "move\n"; }
};
template <typename T>
X make_X(T&& arg) {
return X(std::forward<T>(arg));
}
int main() {
auto x1 = make_X(1); // 1x converting ctor invoked
auto x2 = X(X(1)); // 1x converting ctor invoked
auto x3 = make_X(X(1)); // 1x converting and 1x move ctor invoked
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,哪些规则阻碍了移动构造函数被省略?
UPDATE
调用移动构造函数时可能更直接的情况: …
c++ language-lawyer move-semantics copy-elision perfect-forwarding
(我将这个问题限制在C++ 11中,因为我相信在C++ 98中没有通用的方法).
假设我有一组复杂的(在签名方面)模板函数和/或重载函数,我想以完全相同的方式使用这些函数,但使用不同的名称(即别名).
例如:
template<class A, class B, class C>
D fun(A a, B& b, C&& c){ ... }
template<class E, class F>
G fun(H<E> he, F& f){ ... }
... many other versions of fun
Run Code Online (Sandbox Code Playgroud)
现在假设我想要同时重命名(或别名,或转发为更精确)这些函数(即能够为同一函数使用不同的名称而不重写它).这样,在代码的其他部分,我可以使用不同的名称,而无需修改上述代码.
这是正确的方式重命名(别名/转发)fun到gun?
template<typename... Args>
inline auto gun(Args&&... args)->decltype(fun(std::forward<Args>(args)...)){
return fun(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)
template<class A, class B, class C, class = std::enable_if< ... >::type>),是否会decltype在所有情况下转移SFINAE? …这些功能相同吗?
template <class T>
void foo(T && t)
{
bar(std::forward<T>(t));
}
template <class T>
void foo2(T && t)
{
bar(std::forward<decltype(t)>(t));
}
template <class T>
void foo3(T && t)
{
bar(std::forward(t));
}
Run Code Online (Sandbox Code Playgroud)
如果是,我可以一直使用这个宏来完美转发吗?
#define MY_FORWARD(var) std::forward<decltype(var)>(var)
Run Code Online (Sandbox Code Playgroud)
或者只是使用
bar(std::forward(t));
Run Code Online (Sandbox Code Playgroud)
我相信foo2并且foo3是一样的,但是我发现人们总是像前进一样使用foo,有没有理由明确写出类型?
据我所知,T和T&&两种不同的类型,但我认为std::forward<T>并std::forward<T&&>始终给予同样的结果?
编辑:
我想使用宏的原因是我想在以下C++ 1y代码上保存一些打字,我在不同的地方有很多类似的代码
#define XLC_FORWARD_CAPTURE(var) var(std::forward<decltype(var)>(var))
#define XLC_MOVE_CAPTURE(var) var(std::move(var))
template <class T, class U>
auto foo(T && func, U && para )
{
auto val = // …Run Code Online (Sandbox Code Playgroud) 在这个例子中,Scott Meyers明确了rvalue引用和转发引用之间的区别:
Widget&& var1 = someWidget; // here, “&&” means rvalue reference (1)
auto&& var2 = var1; // here, “&&” does not mean rvalue reference (2)
template<typename T>
void f(std::vector<T>&& param); // here, “&&” means rvalue reference (3)
template<typename T>
void f(T&& param); // here, “&&”does not mean rvalue reference (4)
Run Code Online (Sandbox Code Playgroud)
本质上,当我们有一个可推导的上下文时就会出现这种区别,因此案例(3)明确表明我们有一个,vector<...>&&而T案例(4)是要推断的,并且(在应用参考折叠规则之后)按"价值类别"分类.
但是更复杂的模式匹配会发生什么?以下面的情况为例:
template <template <class...> class Tuple, class... Ts>
void f(Tuple<Ts...>&& arg)
{
}
Run Code Online (Sandbox Code Playgroud)
&&这里的意思是什么?
请考虑以下代码:
template<typename T> void foo(T&& some_struct)
{
bar(std::forward</* what to put here? */>(some_struct.member));
}
Run Code Online (Sandbox Code Playgroud)
在转发整个结构的情况下,我会这样做std::forward<T>(some_struct).但是如何在转发会员时获得正确的类型?
我有一个想法是使用decltype(some_struct.member),但似乎总是产生该成员的基本类型(如结构定义中所定义).
c++ ×10
c++11 ×7
c++14 ×2
auto ×1
constructor ×1
copy-elision ×1
inheritance ×1
lambda ×1
return ×1
templates ×1