Okt*_*ist 13 c++ language-lawyer perfect-forwarding c++11 universal-reference
考虑这段代码,它使用具有函数模板的常用习惯用法构造专门用于推导类型的类模板的实例,如std::make_unique和std::make_tuple以下所示:
template <typename T>
struct foo
{
std::decay_t<T> v_;
foo(T&& v) : v_(std::forward<T>(v)) {}
};
template <typename U>
foo<U> make_foo(U&& v)
{
return { std::forward<U>(v) };
}
Run Code Online (Sandbox Code Playgroud)
在斯科特迈尔斯'通用引用’的上下文中,所述参数
make_foo是一个普遍的基准,因为它的类型是U&&其中U推导出.到的构造函数的参数foo不是通用参考,因为尽管其类型为T&&,T是(通常)不能推导出.
但是在foo调用构造函数的情况下,在make_foo我看来,将构造函数的参数foo看作是一个通用引用可能是有意义的,因为T它是由函数模板推导出来的make_foo.将应用相同的参考折叠规则,以便v两个函数中的类型相同.在这种情况下,无论是T
和U可以说已经推出.
所以我的问题是双重的:
foo在有限的情况下,将构造函数的参数视为通用引用是否有意义T,在调用者的通用引用上下文中,如在我的示例中那样?std::forward明智的用途吗?Ker*_* SB 15
make_foo和"正确"在同一个球场,但foo不是.该foo构造函数目前只接受非推断T &&,转发有可能不是你的意思(但看到@ nosid的评论).总而言之,foo应该采用类型参数,具有模板化构造函数,并且制造商函数应该进行衰减:
template <typename T>
struct foo
{
T v_;
template <typename U>
foo(U && u) : v_(std::forward<U>(u)) { }
};
template <typename U>
foo<typename std::decay<U>::type> make_foo(U && u)
{
return foo<typename std::decay<U>::type>(std::forward<U>(u));
}
Run Code Online (Sandbox Code Playgroud)
在C++ 14中,maker函数变得更简单:
template <typename U>
auto make_foo(U && u)
{ return foo<std::decay_t<U>>(std::forward<U>(u)); }
Run Code Online (Sandbox Code Playgroud)
在您的代码现在编写时,int a; make_foo(a);将创建一个类型的对象foo<int &>.这将在内部存储一个int,但它的构造函数只接受一个int &参数.相比之下,make_foo(std::move(a))会创造一个foo<int>.
所以你编写它的方式,类模板参数决定了构造函数的签名.(std::forward<T>(v)仍然以一种变态的方式有意义(感谢@nodis指出这一点),但这绝对不是"转发".)
这很不寻常.通常,类模板应确定相关的包装类型,构造函数应接受可用于创建包装类型的任何内容,即构造函数应为函数模板.
| 归档时间: |
|
| 查看次数: |
1052 次 |
| 最近记录: |