我正在尝试编写一个可交换的类模板S<T>
。如果T
是可交换的,我希望S<T>
和S<T&>
也是可交换的(例如S<int>
应该可以与S<int&>
交换)。所以我写了这样的东西:
#include <type_traits>
namespace n {
template <typename T>
struct S {};
// Overload #1
template <typename T, typename U>
void swap(S<T>&, S<U>&) {}
// Overload #2
// template <typename T>
// void swap(S<T>&, S<T>&) {}
} // namespace n
int main() {
n::S<int> sInt;
swap(sInt, sInt);
// static_assert(std::is_swappable_v<decltype(sInt)>);
// ^ assertion fails unless I uncomment #2
n::S<int&> sIntRef;
swap(sInt, sIntRef);
static_assert(
std::is_swappable_with_v<decltype(sInt)&, decltype(sIntRef)&>);
// ^ assertion evaluates the way I expect
}
正如你在上面看到的,is_swappable_v<n::S<int>>
是false
,即使对swap(sInt, sInt)
的调用编译了。为了让is_swappable_v<n::S<int>>
计算为true
,我需要取消swap
的重载#2
的注解。
是我做错了什么,还是类型trait std::is_swappable
实际上应该这样工作?
1条答案
按热度按时间8nuwlpux1#
表达式
swap(sInt, sInt)
实际上并不执行swap,因为std::swap
不可见(通过using std::swap;
)。当你拥有它时:
它不会编译,因此类型实际上不能与自身交换。
原因是有两种可能的过载:
第一个更好,因为每个参数都更专业。
第二个会更好,因为两个参数是相同的,它们来自同一个模板参数。
由于它们在不同方面都更好,这使得它成为一个模糊的呼叫。
添加第二个模板重载时:
这比第一个
n::swap
更好,因为它有重复的参数,也比std::swap
更好,因为它更特殊,所以它是明确选择的。