std::make_unique SFINAE 友好吗?
Is std::make_unique SFINAE-friendly?
我正在做一些模板元编程,我想实现一个通用克隆函数,该函数根据表达式的有效性通过 SFINAE(替换失败不是错误)选择克隆方法。
The function
make_unique<T>( std::forward<Args>(args)... )
is equivalent to:
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()
?
如果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);
...必须 returns 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);
- Remarks: This function shall not participate in overload resolution unless T is not an array.
- Returns:
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);
}
我正在做一些模板元编程,我想实现一个通用克隆函数,该函数根据表达式的有效性通过 SFINAE(替换失败不是错误)选择克隆方法。
The function
make_unique<T>( std::forward<Args>(args)... )
is equivalent to:
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()
如果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);
...必须 returns 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);
- Remarks: This function shall not participate in overload resolution unless T is not an array.
- Returns:
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);
}