我认为 is_swappable
的“正确”实现如下:
template<class T, class U = T> struct is_swappable<T, U> : /* see below */ { }
is_swappable
继承自 std::true_type
如果 T 和 U 是 Swappable
, 否则来自 std::false_type
.
我尝试了很多方法,但 SFINAE 似乎不起作用。这是一个特别讨厌的反例:
struct A {
A() {}
~A() {}
A(const A&) = delete;
A(A&&) = delete;
};
显然 A
不是 Swappable
.然而,我能提出的任何通用解决方案都无法正确处理上述示例。
我尝试过但没有成功的 SFINAE 实现如下所示:
namespace with_std_swap {
using std::swap;
template<class T, class U, class =
decltype(swap(std::declval<T&>(), std::declval<U&>()))>
std::true_type swappable_test(int);
template<class, class> std::false_type swappable_test(...);
}
template<class T, class U = T>
struct is_swappable
: decltype(with_std_swap::using_std_swap::swappable_test<T, U>(0)) { };
有没有办法在没有编译器帮助的情况下编写 is_swappable
代码?
最佳答案
基于@jrok 的回答,我们可以通过编写一个 swap
函数来判断一个不合格的 swap
调用是否会调用 std::swap
与 std::swap
相同的签名,但可以检查的唯一返回类型:
namespace detail2 {
struct tag {};
template<class T>
tag swap(T&, T&);
template<typename T>
struct would_call_std_swap_impl {
template<typename U>
static auto check(int)
-> std::integral_constant<bool, std::is_same<decltype( swap(std::declval<U&>(), std::declval<U&>())), tag>::value>;
template<typename>
static std::false_type check(...);
using type = decltype(check<T>(0));
};
template<typename T>
struct would_call_std_swap : would_call_std_swap_impl<T>::type { };
}
那么is_swappable
的定义就变成了:
template<typename T>
struct is_swappable :
std::integral_constant<bool,
detail::can_call_swap<T>::value &&
(!detail2::would_call_std_swap<T>::value ||
(std::is_move_assignable<T>::value &&
std::is_move_constructible<T>::value))
> { };
我们还需要一个特殊情况来交换数组:
template<typename T, std::size_t N>
struct is_swappable<T[N]> : is_swappable<T> {};
关于c++ - 什么是实现 is_swappable 以测试 Swappable 概念的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26744589/