use*_*708 8 c++ perfect-forwarding type-deduction c++14
考虑这个最小的例子
template <class T>
class Foo
{
public:
Foo(const T& t_)
: t(t_)
{
}
Foo(T&& t_)
: t(std::move(t_))
{
}
T t;
};
template <typename F>
Foo<F> makeFoo(F&& f)
{
return Foo<F>(std::forward<F>(f));
}
int main()
{
class C
{
};
C c;
makeFoo(c);
}
Run Code Online (Sandbox Code Playgroud)
MSVC 2017失败,并出现Foo ctor的重新定义错误。显然,T被推导为C&而不是预期的C。这是如何发生的,以及如何修改代码以使其达到预期的目的:从const引用复制构造Foo :: t或从r-移动构造值。
在C ++ 17中,您可以简单地编写:
template <typename F>
auto makeFoo(F&& f)
{
return Foo(std::forward<F>(f));
}
Run Code Online (Sandbox Code Playgroud)
由于类模板参数的推导。
在C ++ 14中,您可以编写:
template <typename F>
auto makeFoo(F&& f)
{
return Foo<std::decay_t<F>>(std::forward<F>(f));
}
Run Code Online (Sandbox Code Playgroud)
template <class F, class R = std::decay_t<F>>
Foo<R> makeFoo(F&& f)
{
return Foo<R>(std::forward<F>(f));
}
Run Code Online (Sandbox Code Playgroud)
这是解决问题的一种干净简单的方法。
衰减是将类型转换为适合存储在某处的类型的一种适当方法。它对数组类型做不好的事情,但是在其他方面做得差不多。您的代码无论如何都不适用于数组类型。
编译器错误是由于引用折叠规则引起的。
X X& X const& X&&
int int& int const& int&&
int& int& int& int&
int const int const& int const& int const&&
int&& int& int& int&&
int const& int const& int const& int const&
Run Code Online (Sandbox Code Playgroud)
这些看起来很奇怪。
第一条规则是const引用是引用,但是对const的引用是不同的。您不能限定“参考”部分;您只能const限定所引用的部分。
当你有T=int&,当你计算T const或时const T,你就会得到int&。
第二部分与如何一起使用r和l值引用有关。当你这样做int& &&或int&& &(你不能直接做,而是你做T=int&那么T&&或T=int&&和T&),你总是一个左参考- T&。左值胜过右值。
然后,我们添加有关如何T&&推导类型的规则;如果传递一个可变的类型的左值C,则进入T=C&对的调用makeFoo。
所以你有:
template<F = C&>
Foo<C&> makeFoo( C& && f )
Run Code Online (Sandbox Code Playgroud)
作为您的签名,又名
template<F = C&>
Foo<C&> makeFoo( C& f )
Run Code Online (Sandbox Code Playgroud)
现在我们来看一下Foo<C&>。它有两个ctor:
Foo( C& const& )
Foo( C& && )
Run Code Online (Sandbox Code Playgroud)
对于第一个,const在引用上将被丢弃:
Foo( C& & )
Foo( C& && )
Run Code Online (Sandbox Code Playgroud)
接下来,对引用的引用就是引用,左值引用胜过右值引用:
Foo( C& )
Foo( C& )
Run Code Online (Sandbox Code Playgroud)
然后,我们走了两个相同的签名构造函数。
TL; DR-在此答案的开头进行操作。
| 归档时间: |
|
| 查看次数: |
123 次 |
| 最近记录: |