虽然我认为您的实现没有固有的概念缺陷,但我会提出三点建议。
(note:我将在这里提到这个概念的实现交换右值 as swap_rvalues
)
从模板推导中排除 const 类型
Assuming
template <typename A, typename B>
struct is_same_no_ref
: std::is_same<
typename std::remove_reference<A>::type,
typename std::remove_reference<B>::type
>
{};
改变启用条件 from std::enable_if<std::is_same_no_ref<A, B>::value>
进入以下内容。
std::enable_if<
std::is_same_no_ref<A, B>::value &&
!std::is_const<typename std::remove_reference<A>::type>::value &&
!std::is_const<typename std::remove_reference<B>::type>::value
>
不从模板推导中排除 const 类型,将 const 变量传递给swap_rvalues
,如下所示,
int const a = 0, b = 0;
swap_rvalues(a, b);
导致编译器标记有关内部实现细节的错误,这对用户来说不太友好。
移动启用条件返回类型声明
代替
template<typename A, typename B, typename = typename std::enable_if<...>::type>
inline void swap_rvalues(A&& a, B&& b);
像下面这样声明它
template<typename A, typename B>
inline typename std::enable_if<...>::type swap_rvalues(A&& a, B&& b);
虽然highly不太可能,第三个模板参数的显式定义swap_rvalues
是可能的,有效地覆盖启用条件。这可能会允许不应该编译的代码被编译,并且可能会出现肮脏的情况。使用返回类型声明可以完全避免这种情况启用条件.
考虑以下示例。
template <
typename A,
typename B,
typename = typename std::enable_if<
is_same_no_ref<A, B>::value &&
!std::is_const<typename std::remove_reference<A>::type>::value &&
!std::is_const<typename std::remove_reference<B>::type>::value
>::type>
inline void
swap(A&& a, B&& b) {
typename std::remove_reference<A>::type t = std::move(a);
a = std::move(b);
b = std::move(t);
}
struct B;
struct A{A(){} A(B const&){}};
struct B{B(){} B(A const&){}};
swap<A, B, void>(A(), B());
它可以编译,尽管它显然不应该编译!A
and B
甚至不相关,它们只是碰巧在给定另一个引用的情况下是可构造的。
重用代码[又名KISS http://en.wikipedia.org/wiki/KISS_principle]
由于右值已经是给了一个名字, 只需转发呼叫std::swap http://en.cppreference.com/w/cpp/algorithm/swap,而不是提供一个全新的实现swap_rvalues
.
Why 重新发明轮子 http://en.wikipedia.org/wiki/Reinventing_the_wheel†? std::swap
一旦右值就已经提供了预期的行为被赋予名字,那么为什么不重用它呢?
结论
最终的实现swap_rvalues
‡ 看起来如下。
template <typename A, typename B>
inline typename std::enable_if<
is_same_no_ref<A, B>::value &&
!std::is_const<typename std::remove_reference<A>::type>::value &&
!std::is_const<typename std::remove_reference<B>::type>::value
>::type
swap_rvalues(A&& a, B&& b) {
std::swap(a, b);
}
脚注
† "To reinvent the wheel is to duplicate a basic method that has already previously been created or optimized by others."
‡ swap_rvalues
in fact would better be called swap
in a real scenario.