【问题标题】:Discrepancy with is_swappable_with_v与 is_swappable_with_v 的差异
【发布时间】:2021-08-19 09:57:39
【问题描述】:

这是this question 的后续行动。稍微修改过的代码版本,使用 std::swappable_with_v 而不是 std::swappable_v 会产生不一致的结果:

#include <type_traits>

template <class T>
struct A {};

template <class T, class U>
constexpr void
swap (A<T>&, A<U>&) {}


int main (){
    static_assert (std::is_swappable_with_v <A <int>,A<double>>);
    using std::swap;
    A<int> a;
    A<double> b;
    swap(a,b);
}

静态断言仅通过 msvc https://godbolt.org/z/G6sj86sfq。虽然所有 3 个主要编译器在删除静态断言时都接受代码:https://godbolt.org/z/hbdq4Eoh1

cppreference 备注:

这个特性不会检查交换表达式的直接上下文之外的任何内容:如果使用 T 或 U 会触发模板特化、隐式定义的特殊成员函数的生成等,并且这些有错误,则实际的交换可能不会即使 std::is_swappable_with::value 编译并计算为 true,也可以编译。

但不应该发生相反的情况,即当在using std::swap 之后成功调用swap 时,该特征应该产生true

gcc 和 clang 拒绝断言是否错误?

【问题讨论】:

    标签: c++ swap typetraits


    【解决方案1】:

    Gcc 和 clang 是正确的。从std::is_swappable_with的行为来看,

    如果表达式swap(std::declval&lt;T&gt;(), std::declval&lt;U&gt;())swap(std::declval&lt;U&gt;(), std::declval&lt;T&gt;())using std::swap 之后的未评估上下文中都是格式良好的;

    std::declval&lt;T&gt;()T 是非左值引用类型时产生右值表达式,用户定义的swap(接受左值引用)和std::swap(接受只有相同的类型),静态断言应该失败。

    您应该将模板参数指定为左值引用:

    static_assert (std::is_swappable_with_v <A <int>&,A<double>&>);
    

    顺便说一句:std::is_swappable 也是这样做的。

    提供一个等于std::is_swappable_with&lt;T&amp;, T&amp;&gt;::value的成员常量值

    【讨论】:

    • 这是否意味着msvc在接受assert时出错了?
    • @463035818_is_not_a_number 是的,因为当T 是非左值引用类型时std::declval&lt;T&gt;() 产生右值表达式,它不应该被用户定义的swapstd::swap 接受。
    猜你喜欢
    • 2011-01-05
    • 2012-03-06
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 2018-12-20
    • 2010-11-07
    • 2010-12-20
    相关资源
    最近更新 更多