Is std::make_unique SFINAE-friendly?

Is std::make_unique SFINAE-friendly?

本文关键字:SFINAE-friendly unique make std Is      更新时间:2023-10-16

我正在进行一些模板元编程,我想实现一个通用的克隆函数,该函数通过SFINAE(替换失败不是错误)根据表达式的有效性选择克隆方法。

在这个参考网站上,它说

功能

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) );
}

即使我有函数CCD_ 1的其他重载?换句话说:std::make_unique() SFINAE友好吗?

如果T而不是可复制构造的,则由于SFINAE,后一个代码将不会参与过载解决。

以下是一个在开启C++14的情况下无法在GCC 5.3上编译的小示例:

#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() ); 
}

标准仅保证:

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);
  1. 备注:除非T不是数组,否则此函数不应参与过载解析
  2. 返回:unique_ptr<T>(new T(std::forward<Args>(args)...))

在您的情况下,您可能希望使用带有my_clone0的版本,或者使用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);
}