为什么 GCC 没有给我一个错误

Why isn't GCC giving me an error

本文关键字:一个 错误 GCC 为什么      更新时间:2023-10-16

GCC并没有给我一个我希望它会出现的例子的错误:

class CannotBeCopied {
public:
    CannotBeCopied(const CannotBeCopied&) = delete;
    CannotBeCopied& operator=(const CannotBeCopied&) =delete;
    CannotBeCopied() { }
    ~CannotBeCopied() { }
};
template<class T>
class FirstVector {
public:
    FirstVector() {
        size = 1;
        data = new T[size];
    }
    ~FirstVector() {
        delete[] data;
    }
    FirstVector(const FirstVector& source) {
        size = source.size;
        data = new T[size];
        for(int k=0;k!=size;k++) {
            data[k] = source.data[k]; //<--I EXPECT AN ERROR HERE
        }
    }
private:
    int size;
    T* data;
};

当不使用复制构造函数时不会发生此错误(也就是说,当使用了复制构造函数时会发生此错误)。

由于模板的原因,我不能简单地将副本ctor移动到代码文件中,并在编译时失败。

我怎么能让它失败呢?

这不是SFINAE,它不应该能够实例化模板。如果复制ctor本身就是一个模板方法(比如说放入:

template<class U=T>

在上面的线路上,那么它将是SFINAE。

我使用的是GCC 4.8.1,当然是-pedantic -Wall -Wextra-std=c++11

我希望通过来失败

int main() { 
    FirstVector<CannotBeCopied> whatever;
}

我知道GCC只是懒惰,没有做它不需要做的工作,但我不喜欢如果我在代码文件中显式实例化这个模板,我会得到一个错误。有没有办法得到我想要的错误?

如果您实际上没有创建模板的实例,则不需要调用复制构造函数-如果您不使用它,甚至不会为CannotBeCopied创建模板代码。调用复制构造函数,您将得到错误:

 FirstVector<CannotBeCopied> a;
 FirstVector<CannotBeCopied> b = a;

编辑:您还可以通过添加来使用模板的所有成员的显式实例化

template class FirstVector<CannotBeCopied>;

(语言规范§14.7.2)

C++中的模板只有在使用时才被物化。其他的都太贵了。

正如你可能听说的,C++模板正在变得完整,所以评估它们可能非常昂贵。IIRC在某个地方有一个Fibonnaci<17> ,它会让编译器计算这个数字。。。

特别是,这意味着死代码将被消除,并且只有当您尝试使用复制构造函数时,c++编译器才会失败。

这不仅仅是GCC懒惰的问题;按照标准,它肯定被禁止做你想让它做的事。[温度指示]/p1,2,11:

1除非类模板专门化已经明确实例化(14.7.2)或显式专用(14.7.3),类当在需要完全定义的对象类型,或者当类的完整性类型会影响程序的语义。[…]的隐式实例化类模板专门化导致声明,但不是定义、默认参数的声明,或类成员函数的异常规范〔…〕

2除非类模板或成员模板的成员显式实例化或显式专门化,专门化当专用化为在需要成员定义存在的上下文中引用。[…]

11实现不应隐式实例化函数模板、变量模板、成员模板、非虚拟成员函数、成员类或类模板的静态数据成员这不需要实例化。

这允许您拥有例如仅移动类型的std::vector。它们的副本构造函数不会编译,但只要不使用它们,std::vector<std::unique_ptr<T>>就完全有效。

为了迫使它失败,您可以在FirstVector:中使用static_assert

static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");

但是,请注意,这只是检查复制构造函数的声明是否可访问且未删除,而不是检查复制构造函数主体是否会编译,这意味着它将错误地报告std::vector<std::unique_ptr<T>>是可复制构造的。

相关文章: