Полное отключение конструктора с помощью `std::enable_if`

У меня есть тип шаблона, который параметризован определенным типом указателя. (как итератор). Я хочу, чтобы этот тип можно было неявно преобразовать в свою версию с квалификатором const (например, thing<const int*>(const thing<int*>&). Я хочу, чтобы этот конструктор был отключен, когда указатель уже равен const, поскольку он конфликтует с конструктором копирования по умолчанию. В настоящее время у меня есть что-то похожее на этот фрагмент кода:

#include <type_traits>

template <typename Ptr>
struct traits {
    using ptr_type = Ptr;
    static constexpr bool is_const = std::is_const_v<std::remove_pointer_t<ptr_type>>;
    template <typename _Ptr> using rebind = traits<_Ptr>;
};

template <typename Traits>
struct thing {
    using ptr_type = typename Traits::ptr_type;
    using non_const_ptr_type = std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<ptr_type>>>;
    using non_const_traits_type = typename Traits::template rebind<non_const_ptr_type>;

    thing(ptr_type p = nullptr) : ptr_(p) {}
    thing(const thing&) = default;

    template <typename = std::enable_if_t<Traits::is_const>>
    thing(const thing<non_const_traits_type>& other) :
        ptr_(const_cast<ptr_type>(other.ptr_)) {}

    ptr_type ptr_;

    template <typename> friend struct thing;
};

int main() {
    thing<traits<      int*>> t;
    thing<traits<const int*>> j(t);
}

Тип thing получает свой параметр из типа характеристик, потому что это более точно представляет мой реальный код. Я пытался отключить конструктор с помощью std::enable_if, но по какой-то причине компилятор продолжает жаловаться на enable_if в non-const thing.

error: no type named 'type' in 'struct std::enable_if<false, void>'
    using enable_if_t = typename enable_if<_Cond, _Tp>::type;

Помещение enable_if в список аргументов конструктора также не помогает. Скомпилировано с помощью GCC 8 с -std=c++17. Вот ссылка Godbolt с кодом.


person Ron    schedule 01.01.2019    source источник
comment
Он должен жаловаться, что нет другого конструктора, который мог бы использовать компилятор. Вам нужно предоставить дополнительный конструктор, когда Traits::is_const имеет значение false.   -  person Corristo    schedule 01.01.2019
comment
А как насчет thing(), thing(ptr_type) и thing(const thing&)? Я не хочу, чтобы четвертый конструктор существовал, когда Traits::is_const равно false.   -  person Ron    schedule 01.01.2019
comment
@Corristo Сообщение об ошибке от thing<traits<int*>> t;. Следует выбрать thing(ptr_type).   -  person    schedule 01.01.2019
comment
Потому что тогда Ptr не const thing(const thing&) и thing(const thing<non_const_traits_type>&) имеют одинаковую подпись.   -  person Ron    schedule 01.01.2019


Ответы (1)


Вам нужно сделать std::enable_if зависимым от параметров шаблона конструктора, а не класса:

template <class T = Traits, typename = std::enable_if_t<T::is_const>>
thing(const thing<non_const_traits_type>& other) :
    ptr_(const_cast<ptr_type>(other.ptr_)) {}
person Jans    schedule 01.01.2019