如果底层类型不是可复制构造的,那么正确的方法是使容器的is_copy_constructible产生错误

Ant*_*vin 6 c++ copy-constructor type-traits c++11

这是std :: unordered_map <T,std :: unique_ptr <U >>可复制的后续内容吗?GCC错误?

所以想象我们创建了一个模板类Container:

template<class T>
class Container {
    T t;
public:
    Container() = default;
    Container(const Container& other) : t(other.t) {}
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,即使不是可复制的,is_copy_constructible它的产量true也是如此T:

static_assert(!std::is_copy_constructible<Container<std::unique_ptr<int>>>::value, "Copyable");
Run Code Online (Sandbox Code Playgroud)

由于上述问题的答案中描述的原因,此断言失败,此处还有关于此主题的另一个答案.

看来这可以通过制作这样的复制consructor模板来修复:

template<class T>
class Container {
    T t;
public:
    Container() = default;

    template<typename U = void>
    Container(const Container& other) : t(other.t) {}
};
Run Code Online (Sandbox Code Playgroud)

这适用于GCC和clang(static_assert不再失败).

Ideone演示

问题:

  1. 从标准的角度来看,这是一种正确的is_copy_constructible工作方式吗?如果是,添加模板如何影响变量initialization(§20.9.4.3/6)的直接上下文的有效性

  2. (可选)有没有更正确或更直观的方法来执行此操作?

注意:声明复制构造函数default也可以实现此目标,但并非总是可行.

更新:现在我看到我的解决方案无效,因为复制构造函数不能是模板.这仍然为问题2留下了空间.

更新2:我从ecatmur的回答中改变了一些代码,将丑陋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)) {}
};
Run Code Online (Sandbox Code Playgroud)

(演示)

但我仍然对此不太满意.对我来说,它似乎是C++标准中的一个缺陷,这些东西不能开箱即用.

eca*_*mur 4

那不是按照你的想法去做;模板构造函数永远不会被视为复制构造函数,因此通过添加template<typename U = void>到复制构造函数,您将诱导编译器创建其自己的默认复制构造函数。

一种可能性(缺少针对非复制构造类型的单独的类模板)是通过将其参数替换为与重载解析无关的内容来禁用复制构造函数:

struct unused;  // forward declaration only

template<typename T>
class Container {
    T t;
public:
    Container() = default;

    Container(
      typename std::conditional<
        std::is_copy_constructible<T>::value,
        Container const&,
        unused>::type other)
      : t(other.t) {}

    Container(Container&& other) : t(std::move(other.t)) {}
};
Run Code Online (Sandbox Code Playgroud)