Bradley Odell
Bradley Odell

Reputation: 1258

Visual Studio 2013 compiling successfully but with obvious error

I'm using Visual Studio Professional 2013. I have a rather odd problem. Normally people post about getting errors - I'm here posting about NOT getting errors.

I have written a custom Matrix class (for homework). I have overriden the assignment operator as follows:

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

I recently changed the newMatrixArray() method to accept a bool parameter:

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

However, Visual Studio still compiles successfully... UNLESS

#include "Matrix.h"

int main() {

    Matrix<int> matrix;

    Matrix<int> otherMatrix;
    otherMatrix = matrix;

    return 0;
}

I write some code that uses the overloaded assignment operator. This is worrying me because now I don't know what else could be broken and Visual Studio isn't telling me!

What's going on with this?

More information:
As you can see, I am using templates. All the Matrix code is in the Matrix.h file - declaration followed by definition. This is required when using templates. The Matrix class is the only class I have right now in my project besides the main.cpp file. I have checked and made sure the declaration and definition match.

Credit: Praetorian
Edit: (SOLUTION)
You can use:

template class NameOfClass<NameOfType>;

to compile template classes against a certain type.

You can also use:

template ReturnType NameOfFunction(Args ... );

to compile outside-of-class methods with template arguments.

These should be placed in the global scope.

Upvotes: 3

Views: 191

Answers (3)

n. m. could be an AI
n. m. could be an AI

Reputation: 120089

The standard basically requires to perform most checks at declaration time. Only checks that cannot be so performed are postponed until instantiation time. The latter checks are those that involve dependent names. See here for a detailed explanation.

Since newMatrixArray is dependent, it will not be checked until instantiation time. And if a member function is never used, it is not instantiated.

The reason for this rule is the fact that the meaning of a dependent name is not fully known until template parameters are known.

The problem with (at least some versions of) MSVC is that even non-dependent names are not checked until instantiation time. You can try to compile this program to check if your compiler is affected. If it compiles, there is a bug.

Upvotes: 0

R Sahu
R Sahu

Reputation: 206737

You said:

This is worrying me because now I don't know what else could be broken and Visual Studio isn't telling me!

What's going on with this?

There is nothing wrong with what the compiler is doing. If a member function of a class template is not used, the function doesn't get instantiated. Some errors will be reported regardless of whether the function is instantiated or not, like mismatched parentheses, but other errors, like the one you mentioned won't be reported unless the function is instantiated.

Upvotes: 1

sp2danny
sp2danny

Reputation: 7687

If something in a template isn't used, it won't be (fully) parsed either, and don't give out errors.
It pretty much have to be this way, and this is not a VS bug, its conformant behaviour.
Consider:

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

If you instance this on a type that is not copyable, it should still work, as long as you
only use work_always

The standard library even uses this, for example vectors resize, that require T to be
default constructible, but vector can still be used on types that aren't, as long as you
dont call any methods requiring it.

This, of course, make template testing a bit hard, you have to make sure to use everything.

Upvotes: 0

Related Questions