enable_if в конструкторе преобразования (stati c cast, is_base_of) - PullRequest
2 голосов
/ 17 февраля 2020

Я работаю над реализацией общего указателя. (используя C ++ 17, если это имеет значение)

Единственная проблема - это конструктор преобразования. Я хочу иметь возможность c привести smart_ptr к smart_ptr базового типа.

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

Работает, но также попытается привести smart_ptr к smart_ptr любого другого типа. Например, если у меня есть перегруженная функция, которая может принимать разные типы smart_ptr несвязанного типа, я получаю ошибку компилятора о неоднозначной перегрузке. Итак, я хочу преобразование из smart_ptr -> smart_ptr, только если U является производным классом от T.

Похоже, это должно работать. Он компилируется, но делает наоборот. Он не позволяет работать действительным сообщениям stati c, но все же разрешает приведение к несвязанным типам:

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

РЕДАКТИРОВАТЬ:

Работает, спасибо за помощь. Я выбираю решение Джарода, так как считаю template <typename U, enable_if_t<is_base_of<T,U>::value, int> = 0> наиболее лаконичным. Я не понимал, что SFINAE может быть таким кратким.

Кроме того, поскольку Натан упомянул об этом:

Как ни странно, одна из проблем, с которыми я столкнулся, заключается в том, что я ожидал, что конструктор копирования шаблона вызываться, когда правая сторона имеет тот же тип. По-видимому, компилятор не считает его реализацией конструктора копирования, а вместо этого вызывается автоматически сгенерированный конструктор копирования. Та же проблема для конструктора перемещения и оператора =. Не уверен, что это ошибка с MSVC2019.

Ответы [ 2 ]

2 голосов
/ 17 февраля 2020

U не выводится с

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

И поскольку это конструктор, вы даже не можете предоставить шаблон явно. Так что этот конструктор бесполезен.

Вместо него можно использовать:

  • Параметр по умолчанию (наиболее похожий на вашу попытку ИМО):

    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)
    {
    // ...
    }
    

И так как вы используете конструктор, вы не можете использовать возвращаемое значение.

2 голосов
/ 17 февраля 2020

Поместите 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)
{

}

И теперь это будет вызываться, только если U равно T или получено из T. Если вы не хотите использовать это, если 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)
{

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...