C++ 为什么“make_”是独一无二的<;T[N]>;`不允许?
假设整个命名空间C++ 为什么“make_”是独一无二的<;T[N]>;`不允许?,c++,language-lawyer,unique-ptr,c++14,C++,Language Lawyer,Unique Ptr,C++14,假设整个命名空间std C++14委员会草案N3690定义了std::make_unique: [n3690:20.9.1.4]:unique\u ptr创建[unique.ptr.create] template unique\u ptr make\u unique(Args&&…Args) 1备注:除非T不是数组,否则此函数不得参与重载解析。 2返回:unique\u ptr(新的T(std::forward(args)…)。 模板唯一性\u ptr使唯一性(大小\u t n) 3备注:除非
std
C++14委员会草案N3690定义了std::make_unique
:
[n3690:20.9.1.4]:
unique\u ptr
创建[unique.ptr.create]
template unique\u ptr make\u unique(Args&&…Args)代码>
1备注:除非T
不是数组,否则此函数不得参与重载解析。
2返回:unique\u ptr(新的T(std::forward(args)…)。
模板唯一性\u ptr使唯一性(大小\u t n)代码>
3备注:除非T
是未知边界的数组,否则此函数不应参与重载解析。
4返回:unique\u ptr(新的typename-remove\u-extent::type[n]())。
模板未指定使_唯一(Args&&…)=delete代码>
5备注:除非T
是已知边界的数组,否则此函数不得参与重载解析
现在,在我看来,这似乎像泥一样清晰,我认为它需要更多的解释。但是,撇开这篇社论评论不谈,我相信我已经破解了每个变体的含义:
template unique\u ptr make\u unique(Args&&…Args)代码>
对于非数组类型,您的bog标准使_唯一
。“备注”可能表示,当T
是数组类型时,某种形式的静态断言或SFINAE技巧会阻止模板成功实例化
在高层,将其视为相当于T*ptr=newt(args)的智能指针代码>
模板唯一性\u ptr使唯一性(大小\u t n)代码>
数组类型的变体。创建动态分配的n
×Ts
数组,并将其包装在唯一的\u ptr
中返回
在高层,将其视为相当于T*ptr=newt[n]的智能指针代码>
模板未指定使_唯一(Args&&…
不允许。“未指定”可能是唯一的
否则,智能指针将相当于无效的T[N]*ptr=new(请保留维度)(维度是常量)T[N]代码>
首先,我说的对吗?如果是这样的话,第三个函数是怎么回事
- 如果不允许程序员在为每个元素提供构造函数参数的同时尝试动态分配数组(就像
newint[5](args)
是不可能的),那么第一个函数不能为数组类型实例化这一事实已经涵盖了这一点,不是吗
- 如果它是为了防止像
T[N]*ptr=newt[N]
(其中N
是一些constexpr
)这样的构造添加到语言中,那么,为什么呢?难道不完全可能存在一个唯一的\u ptr
来包装动态分配的N
×t
s块吗?这会不会是一件坏事,以至于委员会特意禁止使用make_unique
为什么不允许使你独一无二?
引用:
T[N]
从N3485开始,unique\u ptr
没有为t[N]
提供部分专门化。
但是,用户会强烈地倾向于编写make_unique()
。这
这是一个不可能赢的局面。返回unique\u ptr
将选择主
单个对象的模板,这很奇怪。返回unique\u ptr
将是一个例外,否则铁的规则
make_unique()
返回unique_ptr
。因此,
提案使得这里的T[N]
格式错误,允许实现发出
有用的静态\u断言
消息
提案的作者Stephan T.Lavavej(由提供)从1:01:10分钟(或多或少)开始说明了这种情况。对我来说,第三个重载看起来是多余的,因为它不会改变其他重载不匹配的事实,而且它似乎无助于生成更好的错误消息。考虑以下实现:
template< typename T, typename... Args >
typename enable_if< !is_array< T >::value, unique_ptr< T > >::type
make_unique( Args&&... args )
{
return unique_ptr< T >( new T( forward< Args >( args )... ) );
}
template< typename T >
typename enable_if< is_array< T >::value && extent< T >::value == 0, unique_ptr< T > >::type
make_unique( const size_t n )
{
using U = typename remove_extent< T >::type;
return unique_ptr< T >( new U[ n ]() );
}
模板
typename启用\u如果<!是数组:值,唯一的\u ptr:type
使_唯一(Args&&…Args)
{
返回唯一的(新的T(向前的(Args)…);
}
模板
如果::值和范围::值==0,则启用类型名,唯一的\u ptr::类型
使唯一(常数大小)
{
使用U=typename删除\U区段::type;
返回唯一的(新的U[n]());
}
当您尝试调用std::make_unique(1)
时,错误消息将两个候选项都列为已被enable_禁用(如果
)。如果添加第三个已删除的重载,则错误消息将列出三个候选项。另外,由于它被指定为=delete
,您不能在第三个重载的主体中提供更有意义的错误消息,例如,static_assert(sizeof(T)==0,“std::make_shared不允许已知绑定的数组”)代码>
这是你想玩的箱子
第三个重载最终出现在N3656和N3797中的事实可能是由于make_unique
的发展历史,但我想只有STL可以回答:)“除非T不是数组,否则此函数不应参与重载解析。”-是的……我认为答案是@Mehrdad:不是草稿,但是一个新的标准…@Mehrdad:我同意!幸运的是,你的建议很容易遵循,因为到目前为止还没有人这么做