8

I'm searching a way to check function arguments in compile-time if it's possible to do for compiler.

To be more specific: assume that we have some class Matrix.

class Matrix
{
    int x_size;
    int y_size;

public:
    Matrix(int width, int height):
        x_size{width},
        y_size{height}
    {}
    Matrix():
        Matrix(0, 0)
    {}
};

int main()
{
    Matrix a; // good.
    Matrix b(1, 10); // good.
    Matrix c(0, 4); // bad, I want compilation error here.
}

So, can I check or differentiate behavior (function overloading?) in case of static (source-encoded) values passed to function?

If value isn't static:

std::cin >> size;
Matrix d(size, size);

we're only able to do runtime checks. But if values are encoded in source? Can I make compile-time check in this case?

EDIT: I think this can be possible with constexpr constructor, but anyway overloading with and without constexpr isn't allowed. So problem can't be resolved in way I suppose.

Alexander Sergeyev
  • 922
  • 10
  • 19
  • I don't think it is possible to break the compilation if someone pass wrong arguments. Normal way is to throw exception on wrong values – BЈовић Sep 24 '13 at 12:46

4 Answers4

6

To get a compile time error you would need a template:

template <int width, int height>
class MatrixTemplate : public Matrix
{
    static_assert(0 < width, "Invalid Width");
    static_assert(0 < height, "Invalid Height");
    public:
    MatrixTemplate()
    : Matrix(width, height)
    {}
};

(Btw.: I suggest unsigned types for indices)

If you do not have static_assert (here I switch to unsigned):

template <unsigned width, unsigned height>
class MatrixTemplate : public Matrix
{
    public:
    MatrixTemplate()
    : Matrix(width, height)
    {}
};

template <> class MatrixTemplate<0, 0> {};
template <unsigned height> class MatrixTemplate<0, height> {};   
template <unsigned width> class MatrixTemplate<width, 0> {};

There is no support for empty matrices (MatrixTemplate<0, 0>), here. But it should be an easy task to adjust the static_asserts or class MatrixTemplate<0. 0>.

  • That's the puppy! I was just about to code this. Have an upvote. You can also do this with a `constexpr` but a certain compiler doesn't net support it ;-( – Bathsheba Sep 24 '13 at 12:49
  • 1
    I think about this way, but I assume that matrix sizes aren't constant for Matrix object lifetime. So it works, but inapplicable in my case. – Alexander Sergeyev Sep 24 '13 at 12:52
  • There is a typo in your code: `static_assert<` instead of `static_assert(`. – Lumen Sep 24 '13 at 12:53
  • 1
    @AlexanderSergeev If you want the Matrix size to possibly change at runtime (why?), you will need runtime checking anyway. – Lumen Sep 24 '13 at 12:54
  • @Lumen I'm not going to say I don't need runtime checks, but I want to have both of them. – Alexander Sergeyev Sep 24 '13 at 12:57
  • @Lumen, and why: matrix class is needed to store images and convolution matrix applied to this image. In some cases I need to crop image or add frame to make processing of pixels located close to boundaries easier. – Alexander Sergeyev Sep 24 '13 at 13:08
  • @DieterLücking BTW as you can see in question I needed not to restrict matrix sizes but to make sure that empty matrix have 0x0 size (not 0xn or nx0). – Alexander Sergeyev Sep 24 '13 at 13:40
4

You may add a method like this:

template <int WIDTH, int HEIGHT>
Matrix CreateMatrix()
{
    static_assert(WIDTH > 0, "WIDTH > 0 failed");
    static_assert(HEIGHT > 0, "HEIGHT > 0 failed");

    return Matrix(WIDTH, HEIGHT);
}

int main() {
    Matrix m(0, 2);     // no static check
    Matrix m2 = CreateMatrix<0,2>(); // static check

    return 0;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    Good idea. One could make the factory method `CreateMatrix` a static member function of `Matrix` and make the constructors private. Then every external construction is statically checked (if this is desired). – Lumen Sep 24 '13 at 14:05
1

The way that linear algebra packages tend to do this is to use templates for fixed size matrices, as in:

template<int x, int y> class Matrix { ... }

and an extra class for matrices that can change size at runtime

class DynamicMatrix {...}

You still have to rely on the programmer actually using the first option when they want fixed size matrices, but the template version makes it easy to generate a compiler error when x or y are zero.

us2012
  • 16,083
  • 3
  • 46
  • 62
0

Run-time:

Matrix(int width, int height):
    x_size{width},
    y_size{height}
{
        assert(x_size>0);
        assert(y_size>0);
}

Compile-time (Actually you couldn't do it with function arguments. You can use template ways):

template <size_t WIDTH, size_t HEIGHT>
class Matrix
{
    const size_t x_size = WIDTH;
    const size_t y_size = HEIGHT;

    static_assert(WIDTH > 0, "Width must > 0");
    static_assert(HEIGHT > 0, "Height must > 0");
};
masoud
  • 55,379
  • 16
  • 141
  • 208