std::is_swappable_v 在可交换类模板上为 false

std::is_swappable_v is false on a swappable class template

提问人:paolo 提问时间:3/26/2023 更新时间:3/26/2023 访问量:63

问:

我正在尝试编写一个可交换的类模板。如果可交换,我想要并且是可交换的(例如 应该是可交换的 替换为 )。所以我选择了这样的东西:S<T>S<T>S<T&>TS<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>>falseswap(sInt, sInt)is_swappable_v<n::S<int>>true#2swap

我是做错了什么,还是实际上是类型特征 应该以这种方式工作吗?std::is_swappable

C++ 17 交换 类型特征 C++-标准库

评论

1赞 R2RT 3/26/2023
您的示例似乎在 GCC 和 clang 上编译,仅在 MSVC 上失败。我猜是 MSVC。编辑:哎哟,首先未注释,都失败了。错误?godbolt.org/z/v6jWW4TPWstatic_assert

答:

3赞 Artyer 3/26/2023 #1

表达式实际上不执行交换,因为 std::swap 不可见(通过 )。swap(sInt, sInt)using std::swap;

当你拥有它时:

int main() {
    n::S<int> sInt;

    using std::swap;
    swap(sInt, sInt);
}

它不会编译,因此您的类型实际上无法与自身交换。

这样做的原因是有两个可能的重载:

template <typename T, typename U>
void n::swap(S<T>&, S<U>&);
// with T = int, S = int

template <typename T>
void std::swap(T&, T&);
// with T = n::S<int>

第一个会更好,因为每个论点都更专业。
第二个会更好,因为两个参数是相同的,并且它们来自同一个模板参数。

由于它们都以不同的方式更好,因此它成为一个模棱两可的电话。

添加第二个模板重载时:

template <typename T>
void n::swap(S<T>&, S<T>&);
// with T = int

这比第一个更好,因为反复论证,也比因为它更专业,所以它被明确地选择。n::swapstd::swap