在vector <unique_ptr> </unique_ptr>上使用is_copy_constructible时出现误报

时间:2013-08-23 13:29:42

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

类型特征是否能够处理诸如std::vector < std::unique_ptr <int> >之类的情况并检测到它不是可复制构造的?

以下是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的正确行为,是否有办法检测复制结构是否形成错误?好吧,除了让它无法编译之外。

2 个答案:

答案 0 :(得分:13)

这是因为std::vector的设计存在缺陷。 std::vector定义了复制构造,即使它将无法编译,并依赖于std::vector的用户,如果它无法编译,则不会调用该方法。

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

它可能会被复制到C ++的新迭代中,因为会有很少的代码会破坏。不能说没有代码会破坏,因为你可以拥有依赖于std::is_copy_constructible< std::vector< no_copy_type > >std::true_type或等效表达式的事实的代码,但这是一个非常奇怪的依赖。

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

当我有一个容器需要知道所包含的对象是否可以被安全地复制,比较和排序时,我的工作是专门针对自定义特征类的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 >;

以及<==的类似内容。当我遇到更多的容器类型时,我可以添加更多的特殊化,这些容器类型应该真正将它们的属性转发到他们的数据,或者我可以编写一个更高级的SFINAE容器测试和特征并提取底层值类型并将问题发送给测试关于价值类型。

但根据我的经验,我最终会在std::vector上完成这些测试。

请注意,由于向量已添加“参与重载决策”规则,因此whixh是标准 - 代表“执行SFINAE”测试。

答案 1 :(得分:2)

C ++ 11标准的表49列出了一个类必须满足is_copy_constructable<T>::value才能成为什么条件才真实,而且不幸的是,这个条件并不多:

  

is_constructable<T, const T&>::valuetrue

因此,如果std::vector<T>有一个复制构造函数,它就会通过测试。