为什么 GCC 不给我一个错误

Why isn't GCC giving me an error

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;
};

不使用复制构造函数时不会发生此错误(即使用复制构造函数时会发生)。

由于模板的原因,我不能简单地将复制构造器移动到代码文件中,然后在编译时失败。

我怎样才能让它失败?

这不是SFINAE,应该无法实例化模板。如果 copy-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 懒惰的问题;明确禁止按照标准执行您希望它执行的操作。 [temp.inst]/p1, 2, 11:

1 Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. [...] The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or exception-specifications of the class member functions [...]

2 Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist. [...]

11 An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation.

这允许您拥有,例如,std::vectors 仅移动类型。它们的复制构造函数不会编译,但只要你不使用它们,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>>是可复制构造的。