std::make_pair 使用 CRTP class 调用的奇怪行为

Strange behavior in std::make_pair call with CRTP class

问题

我有一个简单的 CRTP 模式 class BaseInterface 和两个 classes,派生自这个 class:test_dinttest_dint2.

test_dinttest_dint2 之间的区别 - 在 test_dint dtor 中明确声明为 ~test_dint() = default;.

我正在尝试通过调用 std::make_pair 使用类型 <std::intptr_t, test_dint> 制作 std::pair,但编译失败并出现错误:

但是,如果成对的类型更改为 <std::intptr_t, test_dint2> - 所有编译都没有错误。

我不明白 - 为什么明确的 dtor 声明会改变 std::pair 模板的行为?

完整代码

#include <memory>
#include <unordered_map>

template<typename DerivedT>
class enable_down_cast
{  
public:
    DerivedT const& impl() const
    {
        // casting "down" the inheritance hierarchy
        return *static_cast<DerivedT const*>(this);
    }

    DerivedT& impl()
    {
        return *static_cast<DerivedT*>(this);
    }

    //~enable_down_cast() = default;

protected:
    // disable deletion of Derived* through Base*
    // enable deletion of Base* through Derived*
    ~enable_down_cast() = default;

private:  
    using Base = enable_down_cast;  
};

template<typename Impl>
class BaseInterface : public enable_down_cast<Impl>
{
public:
    using handle_type = std::intptr_t;

    BaseInterface() = default;

    // Disable copy
    BaseInterface(const BaseInterface&) = delete;
    BaseInterface& operator=(const BaseInterface&) = delete;

    // Enable move
    BaseInterface(BaseInterface&&) = default;
    BaseInterface& operator=(BaseInterface&&) = default;

    ~BaseInterface() = default;

    handle_type handle() const
    {
        return m_handle;
    }

protected:
    handle_type m_handle{ 0 };

private:
    using enable_down_cast<Impl>::impl;
};

class test_dint : public BaseInterface<test_dint> {
public:
    test_dint() = delete;
    test_dint(const handle_type handle) : 
        BaseInterface<test_dint>()
    {
        m_handle = handle;
    }
    ~test_dint() = default;
};

class test_dint2 : public BaseInterface<test_dint2> {
public:
    test_dint2() = delete;
    test_dint2(const handle_type handle) : 
        BaseInterface<test_dint2>()
    {
        m_handle = handle;
    }
};


int main()
{
    test_dint::handle_type handle = 100500;
    std::make_pair(handle, test_dint{ handle }); // <--- failed ctor
    std::make_pair(handle, test_dint2{ handle });
    return 0;
}

现场演示

https://godbolt.org/z/eee7h47v7

这是因为当你声明析构函数时,你prevent the compiler from generate a move constructor,所以test_dint不再是可移动构造的(也不是可复制构造的,因为它是基础)。


明确声明它会起作用。

test_dint(test_dint&&)=default;