Это является продолжением до std::unordered_map<T,std::unique_ptr<U>> copyable? GCC bug?Правильный способ сделать is_copy_constructible для урожая контейнера ложно, если базовый тип не копировать конструируемую
Итак, представьте, мы создали шаблон класса Container
:
template<class T>
class Container {
T t;
public:
Container() = default;
Container(const Container& other) : t(other.t) {}
};
К сожалению, is_copy_constructible
ибо она дает true
даже если T
не копировать конструктивны:
static_assert(!std::is_copy_constructible<Container<std::unique_ptr<int>>>::value, "Copyable");
Это утверждение не подходит по причинам, описанным в ответе на вопрос выше, также here is another answer on this topic.
Оказывается, что это может быть исправлено путем шаблон копирования consructor как это:
template<class T>
class Container {
T t;
public:
Container() = default;
template<typename U = void>
Container(const Container& other) : t(other.t) {}
};
Это работает как в GCC и звоном (static_assert
не подведет больше).
вопросы:
С точки зрения стандарта, это правильный способ сделать
is_copy_constructible
работу? Если да, то как добавление шаблона влияет на на справедливость контекста инициализации переменной (§20.9.4.3/6
)?(необязательно) Есть ли более правильные или более интуитивные способы сделать это?
Примечание: объявление конструктора копии default
также достигает этой цели, но не всегда возможно.
UPDATE: Теперь я вижу, что мое решение недействительно, поскольку конструктор копирования не может быть шаблоном. Это все еще оставляет место для вопроса 2.
UPDATE 2: Я немного изменился код с ecatmur's answer двигаться уродство из Container
себя и сделать его многоразовым:
struct unused; // forward declaration only
template<class Container>
using const_ref_if_copy_constructible = typename std::conditional<
std::is_copy_constructible<typename Container::value_type>::value,
Container const&,
unused>::type;
template<typename T>
class Container {
T t;
public:
typedef T value_type;
Container() = default;
Container(const_ref_if_copy_constructible<Container> other) : t(other.t) {}
Container(Container&& other) : t(std::move(other.t)) {}
};
Но все же я не совсем доволен этим. Для меня это выглядит как недостаток в стандарте C++, что такие вещи не работают из коробки.
Имейте в виде, что «сделать копию т е р шаблон» не должно реально работать - конкретизация шаблона функции никогда не рассматриваются как копия т е р, так что компилятор должен добавить один, если все, что вы предоставляете, является шаблоном. – Angew