【问题标题】:Visual Studio 2013 compiling successfully but with obvious errorVisual Studio 2013 编译成功但有明显错误
【发布时间】:2015-02-20 04:38:25
【问题描述】:

我正在使用 Visual Studio Professional 2013。我遇到了一个很奇怪的问题。通常人们会发布关于出错的帖子 - 我在这里发布关于没有出错的帖子。

我编写了一个自定义矩阵类(用于家庭作业)。 我已经按如下方式覆盖了赋值运算符:

template<typename T>
Matrix<T>& Matrix<T>::operator=(const Matrix<T> &other) {
    if (this != &other) {
        if (this->mRows != other.mRows || this->nColumns != other.nColumns) {
            deleteMatrixArray();
            this->mRows = other.mRows;
            this->nColumns = other.nColumns;
            newMatrixArray();
        } // else reuse the existing array
        // copy contents
        for (unsigned int i = 0; i < this->mRows; i++) {
            for (unsigned int j = 0; j < this->nColumns; j++) {
                this->matrix[i][j] = other.matrix[i][j];
            }
        }
    }
    return *this;
}

我最近更改了 newMatrixArray() 方法以接受 bool 参数:

template<typename T>
void Matrix<T>::newMatrixArray(bool init) {
    this->matrix = new T*[this->mRows];
    for (unsigned int i = 0; i < this->mRows; i++) {
        if (init) {
            this->matrix[i] = new T[this->nColumns]();
        } else {
            this->matrix[i] = new T[this->nColumns];
        }
    }
}

但是,Visual Studio 仍然可以成功编译...除非

#include "Matrix.h"

int main() {

    Matrix<int> matrix;

    Matrix<int> otherMatrix;
    otherMatrix = matrix;

    return 0;
}

我编写了一些使用重载赋值运算符的代码。 这让我很担心,因为现在我不知道还有什么可能被破坏,而 Visual Studio 也没有告诉我!

这是怎么回事?

更多信息:
如您所见,我正在使用模板。所有 Matrix 代码都在 Matrix.h 文件中 - 声明后跟定义。这在使用模板时是必需的。 Matrix 类是我现在项目中除了 main.cpp 文件之外唯一的类。我已经检查并确保声明和定义匹配。

出处:Praetorian
编辑:(解决方案)
您可以使用:

template class NameOfClass<NameOfType>;

针对特定类型编译模板类。

你也可以使用:

template ReturnType NameOfFunction(Args ... );

使用模板参数编译类外方法。

这些应该放在全局范围内。

【问题讨论】:

  • 请提供一个完整但最小的例子供读者试用。
  • 这不是错误的行为,类模板的成员函数只有在你使用它们时才会被实例化。如果要强制实例化,则通过在 main.cpp 的全局范围内添加行 template class Matrix&lt;int&gt;; 来显式实例化 Matrix&lt;int&gt;。那么即使没有otherMatrix = matrix; 赋值,你的代码也不会编译。
  • 看起来很像this question,基本上只有你尝试使用它才会失败。
  • @Praetorian 谢谢!这揭示了类方法实现中的几个错误。我还重载了输入/输出运算符,但它们在类的“外部”并且仍然没有得到检查。 :( 我想我必须手动使用它们来编译它们。
  • @BradleyOdell 你也可以对函数模板做同样的事情,比如template std::ostream&amp; operator&lt;&lt;&lt;int&gt;(std::ostream&amp;, Matrix&lt;int&gt; const&amp;);

标签: c++ visual-studio compiler-errors


【解决方案1】:

你说:

这让我很担心,因为现在我不知道还有什么可能被破坏,而 Visual Studio 也没有告诉我!

这是怎么回事?

编译器所做的并没有错。如果未使用类模板的成员函数,则该函数不会被实例化。无论函数是否实例化,都会报告一些错误,例如不匹配的括号,但其他错误,例如您提到的错误,除非函数被实例化,否则不会报告。

【讨论】:

  • @n.m.,我快速浏览了标准中处理模板实例化的部分,但找不到任何可以最终证明 MSVC 行为不符合标准的内容。我会仔细看的。
  • 对不起,这是我的错误。我正在考虑的错误与这里无关。 newMatrixArray 是一个从属名称,因此不应检查它。错误是 MSVC 甚至对非依赖名称也不进行检查。
【解决方案2】:

如果模板中的某些东西没有被使用,它也不会被(完全)解析,也不会出现错误。
它几乎必须是这种方式,这不是一个 VS 错误,它的行为是一致的。
考虑:

template<typename T>
class X
{
public:
    void work_always(const T&) {}
    void requires_copyable(T) {}
};

如果你在一个不可复制的类型上实例化它,它应该仍然可以工作,只要你
只使用work_always

标准库甚至使用这个,例如向量调整大小, 要求 T 为
默认可构造,但 vector 仍可用于不可构造的类型, 只要你
不要调用任何需要它的方法。

这当然会使模板测试有点困难,你必须确保使用所有东西。

【讨论】:

    【解决方案3】:

    该标准基本上要求在声明时执行大多数检查。只有无法执行的检查才会推迟到实例化时间。后面的检查是那些涉及依赖名称的检查。详细解释见here

    由于newMatrixArray 是依赖的,直到实例化时才会被检查。如果一个成员函数从未被使用过,它就不会被实例化。

    这个规则的原因是依赖名称的含义在知道模板参数之前是不完全知道的。

    MSVC(至少某些版本)的问题在于,即使是非依赖名称也不会在实例化时进行检查。您可以尝试编译this program 以检查您的编译器是否受到影响。如果它编译,有一个错误。

    【讨论】:

      猜你喜欢
      • 2013-02-18
      • 1970-01-01
      • 2014-01-06
      • 1970-01-01
      • 2019-04-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-24
      • 1970-01-01
      相关资源
      最近更新 更多