std::make_unique SFINAE 友好吗?
Posted
技术标签:
【中文标题】std::make_unique SFINAE 友好吗?【英文标题】:Is std::make_unique SFINAE-friendly? 【发布时间】:2016-04-28 12:45:56 【问题描述】:我正在做一些模板元编程,我想实现一个通用克隆函数,该函数通过 SFINAE(替换失败不是错误)根据表达式的有效性选择一种克隆方法。
this reference website 上面写着
功能
make_unique<T>( std::forward<Args>(args)... )
相当于:
unique_ptr<T>(new T(std::forward<Args>(args)...))
这是否意味着下面的代码
template <typename T>
auto my_clone( const T & t ) -> decltype( std::make_unique<T>(t) )
return std::make_unique<T>(t);
应该完全等价于
template <typename T>
auto my_clone( const T & t ) -> decltype( std::unique_ptr<T>( new T(t) ) )
return std::unique_ptr<T>( new T(t) );
即使我有函数my_clone
的其他重载?换句话说:是std::make_unique()
SFINAE-friendly?
如果T
不是可复制构造,则由于 SFINAE,后一个代码将不会参与重载决议。
下面是一个在 GCC 5.3 上编译失败且 C++14 开启的小例子:
#include <memory>
// It does **not** work with this snippet:
template <typename T>
auto my_clone( const T & t ) -> decltype( std::make_unique<T>( t ) )
return std::make_unique<T>( t );
/* // But it works with this snippet instead:
template <typename T>
auto my_clone( const T & t ) -> decltype( std::unique_ptr<T>( new T(t) ) )
return std::unique_ptr<T>( new T(t) );
*/
// This is another overload for testing purposes.
template <typename T>
auto my_clone( const T & t ) -> decltype(t.clone())
return t.clone();
class X
public:
X() = default;
auto clone() const
return std::unique_ptr<X>( new X(*this) );
private:
X( const X & ) = default;
;
int main()
// The following line produces the compiler error:
// "call to 'my_clone' is ambiguous"
const auto x_ptr = my_clone( X() );
【问题讨论】:
标准不保证,请勿依赖。 @Holt 标准不能保证什么?在 [unique.ptr.create] 它声明make_unique
返回:unique_ptr<T>(new T(std::forward<Args>(args)...))
.
@NathanOliver 是,但标准不保证如果 T
不能使用 Args&&...
构造,则 std::make_unique(Args&&...)
不应该存在。
@Holt 好吧。我只是不确定你在说什么。
在您的情况下,您可以改用std::is_copy_constructible
特征。
【参考方案1】:
该标准仅保证:
template <class T, class... Args> unique_ptr<T> std::make_unique(Args&&... args);
...必须返回unique_ptr<T>(new T(std::forward<Args>(args)...))
,它不保证make_unique
函数应该仅在T
可以使用Args...
构造时才存在,所以它不是SFINAE 友好的(根据标准),所以你不能依赖它。
标准中唯一提到make_unique
的部分:
§20.8.1.4 [unique.ptr.create]:
template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
备注:除非 T 不是数组,否则此函数不应参与重载决议。 返回:
unique_ptr<T>(new T(std::forward<Args>(args)...))
。
在您的情况下,您可能希望使用带有std::unique_ptr<T>(new T(...))
的版本或使用is_copy_constructible
以使您的my_clone
SFINAE 友好(@Yakk、@Jarod42),例如:
template <typename T,
typename = std::enable_if_t<std::is_copy_constructible<T>::value>>
auto my_clone(const T & t) -> decltype(std::make_unique<T>(t))
return std::make_unique<T>(t);
【讨论】:
一定会喜欢那个三重否定的:)以上是关于std::make_unique SFINAE 友好吗?的主要内容,如果未能解决你的问题,请参考以下文章
Valgrind 在 std::make_unique 中显示内存泄漏
通过 make_unique/make_shared 调用 initializer_list 构造函数