我认为"适当"的实现is_swappable如下:
template<class T, class U = T> struct is_swappable<T, U> : /* see below */ { }
Run Code Online (Sandbox Code Playgroud)
is_swappable从std::true_typeT和U 继承Swappable,否则从std::false_type.
我尝试了很多东西,但SFINAE似乎没有用.这是一个特别讨厌的反例:
struct A {
A() {}
~A() {}
A(const A&) = delete;
A(A&&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
显然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)) { };
Run Code Online (Sandbox Code Playgroud)
有is_swappable没有编译器帮助的代码?
经过深思熟虑,其他答案提出的想法,并发现 C++ 标准中的缺陷,我认为我已经得到了尽可能接近该Swappable概念的编译时检查的解决方案。
这并不漂亮。它使用一种技巧来检测是否使用了TCstd::swap所提议的具有完全相同签名的函数。然后我们编写辅助函数来检测交换是否可能,以及它是否解析为. 最后一个辅助模板用于查看是否为 noexcept。这没有使用 C++14 标准中提出的确切语义,并假设我认为交换多维数组的预期行为是.std::swapstd::swapnoexcept
namespace detail {
namespace swap_adl_tests {
// if swap ADL finds this then it would call std::swap otherwise (same signature)
struct tag {};
template<class T> tag swap(T&, T&);
template<class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
// helper functions to test if an unqualified swap is possible, and if it becomes std::swap
template<class, class> std::false_type can_swap(...) noexcept(false);
template<class T, class U, class = decltype(swap(std::declval<T&>(), std::declval<U&>()))>
std::true_type can_swap(int) noexcept(
noexcept(swap(std::declval<T&>(), std::declval<U&>()))
);
template<class, class> std::false_type uses_std(...);
template<class T, class U>
std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag> uses_std(int);
template<class T>
struct is_std_swap_noexcept : std::integral_constant<bool,
std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value
> { };
template<class T, std::size_t N>
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> { };
template<class T, class U>
struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> { };
}
}
template<class T, class U = T>
struct is_swappable : std::integral_constant<bool,
decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
(std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))
> {};
template<class T, std::size_t N>
struct is_swappable<T[N], T[N]> : std::integral_constant<bool,
decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
(!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
is_swappable<T, T>::value)
> {};
template<class T, class U = T>
struct is_nothrow_swappable : std::integral_constant<bool,
is_swappable<T, U>::value && (
(decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
detail::swap_adl_tests::is_std_swap_noexcept<T>::value)
||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value)
)
> {};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
886 次 |
| 最近记录: |