在矢量上使用is_copy_constructible时出现误报

问题描述 投票:13回答:2

类型特征是否应该能够处理诸如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的正确行为,有没有办法检测复制结构是否形成错误?好吧,除了让它无法编译之外。

c++ c++11 typetraits g++4.8
2个回答
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可能会使它更清晰,并且更容易包含在语言的新迭代中。

当我有一个容器需要知道所包含的对象是否可以被安全地复制,比较和排序时,我的工作是专门针对自定义traits类上的std::vector,并回退到包含类型上的自定义traits类的值。这是一个拼凑的解决方案,非常具有侵入性。

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是标准 - 代表“do SFINAE”测试。


2
投票

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

is_constructable<T, const T&>::valuetrue

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

© www.soinside.com 2019 - 2024. All rights reserved.