enable_if 在转换构造函数上(静态转换,is_base_of)

enable_if on conversion constructor (static cast, is_base_of)

我正在研究共享指针的实现。 (使用 C++17,以防万一)

唯一的问题是转换构造函数。我希望能够将 smart_ptr 静态转换为基本类型的 smart_ptr。

template<typename U>
inline smart_ptr(const smart_ptr<U>& rhs)
{
    ...
}

它有效,但它也会尝试将 smart_ptr 转换为任何其他类型的 smart_ptr。例如,如果我有一个重载函数,它可以接受不同类型的 smart_ptr 的不相关类型,我会得到一个关于模糊重载的编译器错误。所以,如果 U 是 T.class 的派生 class,我只想从 smart_ptr -> smart_ptr 进行转换。

这看起来应该可行。它编译,但它做相反的事情。它阻止有效的静态向上转换工作,但仍然允许转换为不相关的类型:

template<typename U>
inline local_shared_ptr(typename enable_if<is_base_of<T,U>::value, const  local_shared_ptr<U>&>::type rhs)
{
    ...
}

编辑:

成功了,感谢您的帮助。我选择 jarod 的解决方案,因为我发现 template <typename U, enable_if_t<is_base_of<T,U>::value, int> = 0> 最简洁。没想到SFINAE可以这么简洁

此外,由于 Nathan 提到了它:

有趣的是,我遇到的问题之一是我希望在右侧是相同类型时调用模板复制构造函数。显然,编译器不认为它是复制构造函数的实现,而是调用了自动生成的复制构造函数。移动构造函数和 operator= 也有同样的问题。不确定这是否是 MSVC2019 的错误。

enable_if放在模板参数列表中,如

template<typename U, std::enable_if_t<std::is_base_of_v<T, U>, bool> = true>
inline smart_ptr(const smart_ptr<U>& rhs)
{

}

现在只有当 UT 或派生自 T 时才会调用它。如果你不想使用这个 if U == T 那么你可以使用

template<typename U, std::enable_if_t<std::is_base_of_v<T, U> && !std::is_same_v<T, U>, bool> = true>
inline smart_ptr(const smart_ptr<U>& rhs)
{

}

U 不可推导出

template<typename U>
local_shared_ptr(enable_if_t<is_base_of<T,U>::value, const  local_shared_ptr<U>&> rhs)
{
// ...
}

因为它是一个构造器,你甚至不能显式地提供模板。 所以那个构造函数是没用的。

您可以改用:

  • 默认参数(与您尝试的 IMO 最相似):

    template <typename U>
    local_shared_ptr(const local_shared_ptr<U>& rhs, enable_if_t<is_base_of<T,U>::value, int> = 0)
    {
    // ...
    }
    
  • 默认模板参数(首选方式):

    template <typename U, enable_if_t<is_base_of<T,U>::value, int> = 0>
    local_shared_ptr(const local_shared_ptr<U>& rhs)
    {
    // ...
    }
    

并且当你使用构造函数时,你不能使用 return 值。