【问题标题】:False positive with is_copy_constructible on vector<unique_ptr>在向量<unique_ptr> 上使用 is_copy_constructible 误报
【发布时间】:2013-08-26 13:55:59
【问题描述】:

类型特征是否应该能够处理std::vector &lt; std::unique_ptr &lt;int&gt; &gt; 之类的情况并检测到它不是可复制构造的?

这是https://ideone.com/gbcRUa 的示例(运行 g++ 4.8.1)

#include <type_traits>
#include <vector>
#include <iostream>
#include <memory>

int main()
{
    // This prints 1, implying that it's copy constructible, when it's clearly not
    std::cout << std::is_copy_constructible< std::vector<std::unique_ptr<int> > >::value << std::endl; 
    return 0;
}

如果这是is_copy_constructible 的正确行为,有没有办法检测出复制结构的格式不正确?好吧,不仅仅是让它无法编译。

【问题讨论】:

  • 很遗憾,是的,这是允许的行为 :(。我继续讨论这个问题,以及为什么我们需要使用 SFINAE 来防止它,这里:flamingdangerzone.com/cxx11/2013/02/11/…
  • @R.MartinhoFernandes:Bleh,我担心你会这么说。我之前没有找到is_constructible 的问题,但答案是一样的,因为is_copy_constructible 指的是is_constructible
  • 是的,这很烦人。您的问题促使我将问题提交到标准提案邮件列表:groups.google.com/a/isocpp.org/d/msg/std-proposals/pgWYGIvV2Tw/…。因为 C++14 提案的截止日期是 8 月 30 日,所以我可能早在 2 月就应该这样做了。
  • @R.MartinhoFernandes:呃,我认为我们可以使用decltype 和一个明确的检查来解决这个问题,但是apparently not,这也是你知道的一个缺陷吗?
  • @MatthieuM。是的,这本质上是同一个问题:decltype 也不会超越当前的上下文。真的没有办法不改变vector :(

标签: c++ c++11 typetraits g++4.8


【解决方案1】:

这是因为std::vector 的设计存在缺陷。 std::vector 定义复制构造,即使编译失败,也依赖std::vector 的用户在编译失败时不调用该方法。

如果vector 中包含的类型没有复制构造函数,则另一种设计是SFINAE 阻止方法的调用。然而,std::vector 是在现代 SFINAE 技术开发之前设计的。

它可能会被重新安装到新的 C++ 迭代中,因为很少有代码会被破坏。不能说没有代码会中断,因为您的代码可能依赖于 std::is_copy_constructible&lt; std::vector&lt; no_copy_type &gt; &gt;std::true_type 或等效表达式这一事实,但这是一种非常奇怪的依赖关系。

除了std::vector 比可以解决此问题的 SFINAE 技术更早的事实之外,使用 SFINAE 这样做非常混乱(因为 SFINAE 是一种混乱的技术)。为 C++1y 提出的新概念精简版可能会使其更简洁,并且更容易包含在该语言的新迭代中。

当我有一个容器需要知道是否可以安全地复制、比较和排序包含的对象时,我的解决方法是专门针对自定义特征类上的std::vector,并依赖于自定义特征的值包含类型的类。这是一个拼凑而成的解决方案,而且非常具有侵入性。

template<template<typename>class test, typename T>
struct smart_test : test<T> {};
template<template<typename>class test, typename T, typename A>
struct smart_test<test, std::vector<T,A>> : smart_test<T> {};

这给了我们:

template<typename T>
using smart_is_copy_constructible = smart_test< std::is_copy_constructible, T >;

&lt;== 也类似。当我遇到更多应该将它们的属性真正转发到它们的数据的容器类型时,我可以添加更多的专业化,或者我可以编写一个更高级的 SFINAE 容器测试和特征并提取底层值类型并将问题分发给测试关于值类型。

但根据我的经验,我主要是在 std::vector 上进行这些测试。

请注意,由于 向量已添加“参与重载解决”规则,这是“执行 SFINAE”测试的标准表述。

【讨论】:

  • 好吧,你给了我一个有趣的解决方法。我已经考虑为 is_copy_constructible 添加一个专门的模板,但我喜欢你给我的一个事实,我可以在多个类型特征上重复使用。
  • 正如发布的那样,代码无法编译 [不仅仅是因为缺少分号]。
  • @degski 从技术上讲,it 编译,你只需要将它与下一个语句或声明分开。 ;)
  • @Yakk-AdamNevraumont 我不明白你所说的“技术上它可以编译”是什么意思,实际上我的编译器说“它不好”。
  • @degski "hello" 是一个复杂的 C++ 字符串,但是如果你输入一个只包含 "hello" 的程序,编译器会报错;您需要在任一侧的代码中包含"hello"。同样,我的作品,从技术上讲,只要它周围的东西后面有一个;。 ;)
【解决方案2】:

C++11 标准的表 49 列出了一个类必须满足哪些条件才能使 is_copy_constructable&lt;T&gt;::value 为真,不幸的是,这并不多:

is_constructable&lt;T, const T&amp;&gt;::valuetrue

所以如果std::vector&lt;T&gt; 有一个复制构造函数,它就会通过测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 2014-07-21
    • 1970-01-01
    • 2021-05-16
    • 1970-01-01
    相关资源
    最近更新 更多