c++ - 如果底层类型不可复制构造,则为容器生成 is_copy_constructible 的正确方法会产生 false

标签 c++ c++11 copy-constructor typetraits

这是 std::unordered_map<T,std::unique_ptr<U>> copyable? GCC bug? 的后续行动

假设我们创建了一个模板类 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 .

看起来这可以通过像这样制作复制构造器模板来解决:

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

    template<typename U = void>
    Container(const Container& other) : t(other.t) {}
};

这在 GCC 和 clang 中都有效(static_assert 不再失败)。

Ideone Demo

问题:

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

  2. (可选)是否有更正确或更直观的方法来做到这一点?

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

更新:现在我发现我的解决方案无效,因为复制构造函数不能是模板。这仍然为问题 2 留有余地。

更新 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)) {}
};

(Demo)

但我对此还是不太满意。对我来说,这看起来像是 C++ 标准中的一个缺陷,因为这些东西不能开箱即用。

最佳答案

那不是按照你的想法去做;模板构造函数永远不会被认为是复制构造函数,因此通过添加 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)) {}
};

关于c++ - 如果底层类型不可复制构造,则为容器生成 is_copy_constructible 的正确方法会产生 false,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25809528/

相关文章:

c++ - 如何将索引变量用于递归函数?

c++ - 将文件与更改数据同步的最佳方法

c++ - 获取模板化函数的地址是否应该触发其编译?

c++ - 如何将类对象推回到 std::vector 中?

c++ - 为什么使用 std::next 而不是向指针添加一个整数?

c++ - 什么时候可以安全且轻松地将引用变量用作别名?

c++ - 动态二维数组的复制构造函数

c++ - Ho 得到一个字符串,直到一个字符的最后一次出现

c++ - 拷贝构造函数问题

c++ - 隐式声明和隐式定义的复制构造函数有什么区别?