过年之无用知识研究:恢复std::pair中被delete了的operator=,会怎样

发布于:2025-02-10 ⋅ 阅读:(58) ⋅ 点赞:(0)

把pair的源码拷贝出来,起个新名字叫MyPair

template<class _Ty1,
    class _Ty2>
    struct MyPair
{	// store a MyPair of values
    using first_type = _Ty1;
    using second_type = _Ty2;

//
// 本文主要是改造这一行
//
    MyPair& operator=(const volatile MyPair&) = delete;

    template<class _Uty1 = _Ty1,
        class _Uty2 = _Ty2,
        enable_if_t<conjunction_v<
        is_default_constructible<_Uty1>,
        is_default_constructible<_Uty2>,
        _Is_implicitly_default_constructible<_Uty1>,
        _Is_implicitly_default_constructible<_Uty2>
    >, int> = 0>
        constexpr MyPair()
        _NOEXCEPT_COND(is_nothrow_default_constructible_v<_Uty1>
            && is_nothrow_default_constructible_v<_Uty2>)	// strengthened
        : first(), second()
    {
    }

    template<class _Uty1 = _Ty1,
        class _Uty2 = _Ty2,
        enable_if_t<conjunction_v<
        is_default_constructible<_Uty1>,
        is_default_constructible<_Uty2>,
        negation<conjunction<
        _Is_implicitly_default_constructible<_Uty1>,
        _Is_implicitly_default_constructible<_Uty2>>>
        >, int> = 0>
        constexpr explicit MyPair()
        _NOEXCEPT_COND(is_nothrow_default_constructible_v<_Uty1>
            && is_nothrow_default_constructible_v<_Uty2>)	// strengthened
        : first(), second()
    {
    }

    template<class _Uty1 = _Ty1,
        class _Uty2 = _Ty2,
        enable_if_t<conjunction_v<
        is_copy_constructible<_Uty1>,
        is_copy_constructible<_Uty2>,
        is_convertible<const _Uty1&, _Uty1>,
        is_convertible<const _Uty2&, _Uty2>
    >, int> = 0>
        constexpr MyPair(const _Ty1& _Val1, const _Ty2& _Val2)
        _NOEXCEPT_COND(is_nothrow_copy_constructible_v<_Uty1>
            && is_nothrow_copy_constructible_v<_Uty2>)	// strengthened
        : first(_Val1), second(_Val2)
    {
    }

    template<class _Uty1 = _Ty1,
        class _Uty2 = _Ty2,
        enable_if_t<conjunction_v<
        is_copy_constructible<_Uty1>,
        is_copy_constructible<_Uty2>,
        negation<conjunction<
        is_convertible<const _Uty1&, _Uty1>,
        is_convertible<const _Uty2&, _Uty2>>>
        >, int> = 0>
        constexpr explicit MyPair(const _Ty1& _Val1, const _Ty2& _Val2)
        _NOEXCEPT_COND(is_nothrow_copy_constructible_v<_Uty1>
            && is_nothrow_copy_constructible_v<_Uty2>)	// strengthened
        : first(_Val1), second(_Val2)
    {
    }

    template<class _Other1,
        class _Other2,
        enable_if_t<conjunction_v<
        is_constructible<_Ty1, _Other1>,
        is_constructible<_Ty2, _Other2>,
        is_convertible<_Other1, _Ty1>,
        is_convertible<_Other2, _Ty2>
    >, int> = 0>
        constexpr MyPair(_Other1&& _Val1, _Other2&& _Val2)
        _NOEXCEPT_COND(is_nothrow_constructible_v<_Ty1, _Other1>
            && is_nothrow_constructible_v<_Ty2, _Other2>)	// strengthened
        : first(_STD forward<_Other1>(_Val1)),
        second(_STD forward<_Other2>(_Val2))
    {
    }

    template<class _Other1,
        class _Other2,
        enable_if_t<conjunction_v<
        is_constructible<_Ty1, _Other1>,
        is_constructible<_Ty2, _Other2>,
        negation<conjunction<
        is_convertible<_Other1, _Ty1>,
        is_convertible<_Other2, _Ty2>>>
        >, int> = 0>
        constexpr explicit MyPair(_Other1&& _Val1, _Other2&& _Val2)
        _NOEXCEPT_COND(is_nothrow_constructible_v<_Ty1, _Other1>
            && is_nothrow_constructible_v<_Ty2, _Other2>)	// strengthened
        : first(_STD forward<_Other1>(_Val1)),
        second(_STD forward<_Other2>(_Val2))
    {
    }

    MyPair(const MyPair&) = default;
    MyPair(MyPair&&) = default;

    template<class _Other1,
        class _Other2,
        enable_if_t<conjunction_v<
        is_constructible<_Ty1, const _Other1&>,
        is_constructible<_Ty2, const _Other2&>,
        is_convertible<const _Other1&, _Ty1>,
        is_convertible<const _Other2&, _Ty2>
    >, int> = 0>
        constexpr MyPair(const MyPair<_Other1, _Other2>& _Right)
        _NOEXCEPT_COND(is_nothrow_constructible_v<_Ty1, const _Other1&>
            && is_nothrow_constructible_v<_Ty2, const _Other2&>)	// strengthened
        : first(_Right.first), second(_Right.second)
    {
    }

    template<class _Other1,
        class _Other2,
        enable_if_t<conjunction_v<
        is_constructible<_Ty1, const _Other1&>,
        is_constructible<_Ty2, const _Other2&>,
        negation<conjunction<
        is_convertible<const _Other1&, _Ty1>,
        is_convertible<const _Other2&, _Ty2>>>
        >, int> = 0>
        constexpr explicit MyPair(const MyPair<_Other1, _Other2>& _Right)
        _NOEXCEPT_COND(is_nothrow_constructible_v<_Ty1, const _Other1&>
            && is_nothrow_constructible_v<_Ty2, const _Other2&>)	// strengthened
        : first(_Right.first), second(_Right.second)
    {
    }

    template<class _Other1,
        class _Other2,
        enable_if_t<conjunction_v<
        is_constructible<_Ty1, _Other1>,
        is_constructible<_Ty2, _Other2>,
        is_convertible<_Other1, _Ty1>,
        is_convertible<_Other2, _Ty2>
    >, int> = 0>
        constexpr MyPair(MyPair<_Other1, _Other2>&& _Right)
        _NOEXCEPT_COND(is_nothrow_constructible_v<_Ty1, _Other1>
            && is_nothrow_constructible_v<_Ty2, _Other2>)	// strengthened
        : first(_STD forward<_Other1>(_Right.first)),
        second(_STD forward<_Other2>(_Right.second))
    {
    }

    template<class _Other1,
        class _Other2,
        enable_if_t<conjunction_v<
        is_constructible<_Ty1, _Other1>,
        is_constructible<_Ty2, _Other2>,
        negation<conjunction<
        is_convertible<_Other1, _Ty1>,
        is_convertible<_Other2, _Ty2>>>
        >, int> = 0>
        constexpr explicit MyPair(MyPair<_Other1, _Other2>&& _Right)
        _NOEXCEPT_COND(is_nothrow_constructible_v<_Ty1, _Other1>
            && is_nothrow_constructible_v<_Ty2, _Other2>)	// strengthened
        : first(_STD forward<_Other1>(_Right.first)),
        second(_STD forward<_Other2>(_Right.second))
    {
    }

    template<class _Tuple1,
        class _Tuple2,
        size_t... _Indexes1,
        size_t... _Indexes2> inline
        MyPair(_Tuple1& _Val1,
            _Tuple2& _Val2,
            index_sequence<_Indexes1...>,
            index_sequence<_Indexes2...>);

    template<class... _Types1,
        class... _Types2> inline
        MyPair(piecewise_construct_t,
            tuple<_Types1...> _Val1,
            tuple<_Types2...> _Val2);

    

    template<class _Other1 = _Ty1,
        class _Other2 = _Ty2,
        enable_if_t<conjunction_v<
        is_assignable<_Ty1&, const _Other1&>,
        is_assignable<_Ty2&, const _Other2&>
    >, int> = 0>
        MyPair& operator=(const MyPair<_Other1, _Other2>& _Right)
        _NOEXCEPT_COND(is_nothrow_assignable_v<_Ty1&, const _Other1&>
            && is_nothrow_assignable_v<_Ty2&, const _Other2&>)	// strengthened
    {
        first = _Right.first;
        second = _Right.second;
        return (*this);
    }

    template<class _Other1 = _Ty1,
        class _Other2 = _Ty2,
        enable_if_t<conjunction_v<
        is_assignable<_Ty1&, _Other1>,
        is_assignable<_Ty2&, _Other2>
    >, int> = 0>
        MyPair& operator=(MyPair<_Other1, _Other2>&& _Right)
        _NOEXCEPT_COND(is_nothrow_assignable_v<_Ty1&, _Other1>
            && is_nothrow_assignable_v<_Ty2&, _Other2>)	// strengthened
    {
        first = _STD forward<_Other1>(_Right.first);
        second = _STD forward<_Other2>(_Right.second);
        return (*this);
    }

    void swap(MyPair& _Right)
        _NOEXCEPT_COND(_Is_nothrow_swappable<_Ty1>::value
            && _Is_nothrow_swappable<_Ty2>::value)
    {
        if (this != _STD addressof(_Right))
        {	// different, worth swapping
            _Swap_adl(first, _Right.first);
            _Swap_adl(second, _Right.second);
        }
    }

    _Ty1 first;		// the first stored value
    _Ty2 second;	// the second stored value
};
测试代码:
MyPair<const int, int> t0;
MyPair<int, int> t1;
t0 = t1;

编译错误:
error C2679: 二进制“=”: 没有找到接受“MyPair<int,int>”类型的右操作数的运算符(或没有可接受的转换)
note: 可能是“MyPair<const int,int> &MyPair<const int,int>::operator =(volatile const MyPair<const int,int> &)”
note: 尝试匹配参数列表“(MyPair<const int,int>, MyPair<int,int>)”时
尝试把delete的MyPair的operator=给个实现呢:
把MyPair& operator=(const volatile MyPair&)=delete;
改为:
MyPair& operator=(const volatile MyPair&)
{

   return (*this);
}


编译错误为:
error C2679: 二进制“=”: 没有找到接受“MyPair<int,int>”类型的右操作数的运算符(或没有可接受的转换)
note: 可能是“MyPair<const int,int> &MyPair<const int,int>::operator =(volatile const MyPair<const int,int> &)”
note: 尝试匹配参数列表“(MyPair<const int,int>, MyPair<int,int>)”时

因为左边的MyPair实例化的是<const int,int>,而
MyPair& operator=(const volatile MyPair&)里括号里的MyPair里实例化的是<int,int>,
按照函数的写法,这两者应该一样。但此时不一样,所以编译错误。

下面编译成功。也就是把operator=采用模板函数,括号里的形参进行单独推导

把MyPair& operator=(const volatile MyPair&) = delete;
改为:
    template<typename T, typename U>
    MyPair& operator=(const volatile MyPair<T, U>& _Right)
    {
        //first = _Right.first;
        //second = _Right.second;
        return (*this);
    }
template<typename T, typename U>
    MyPair& operator=(const volatile MyPair<T, U>& _Right)
    {
//强行把this的first的const给去掉,就可以被参数给赋值了
        using decayType = std::decay_t<_Ty1>;
        decayType& _first = const_cast<decayType&>(first);
        
        _first = _Right.first;
        second = _Right.second;
        return (*this);
    }

测试代码:
编译通过,t0的内容就是(3,4),被成功赋值

MyPair<const int, int> t0{1,2};
MyPair<int, int> t1{ 3,4 };
t0 = t1;
return 1; 


网站公告

今日签到

点亮在社区的每一天
去签到