1

I've some time of experience with C, some less time with OOP in general, but only now have been trying to learn C++. This is an exercise on templates.

I have a simple class:

struct type {

    type(double data = 0) : data(data)
    {
        std::cout << "at type constructor" << std::endl;
    }

    friend std::ostream& operator<<(std::ostream& out, const type &that)
    {
        return out << "[" << std::setfill('0') << std::setw(7) <<
            std::fixed << std::setprecision(2) << that.data << "]";
    }

    private:
        double data;
};

And a basic template:

template<typename T>
struct mat4 {

    T a1, a2, a3, a4;
    T b1, b2, b3, b4;
    T c1, c2, c3, c4;
    T d1, d2, d3, d4;

    mat4 (T a1 = T(), T a2 = T(), T a3 = T(), T a4 = T(),
          T b1 = T(), T b2 = T(), T b3 = T(), T b4 = T(),
          T c1 = T(), T c2 = T(), T c3 = T(), T c4 = T(),
          T d1 = T(), T d2 = T(), T d3 = T(), T d4 = T()) :
        a1(a1), b1(a2), c1(a3), d1(a4),
        a2(b1), b2(b2), c2(b3), d2(b4),
        a3(c1), b3(c2), c3(c3), d3(c4),
        a4(d1), b4(d2), c4(d3), d4(d4)
    {
        std::cout << "at mat4 consctructor" << std::endl;
    }

    friend std::ostream& operator<<(std::ostream& out, const mat4 &that)
    {
        return out << that.a1 << that.a2 << that.a3 << that.a4 << std::endl <<
                  that.b1 << that.b2 << that.b3 << that.b4 << std::endl <<
                  that.c1 << that.c2 << that.c3 << that.c4 << std::endl <<
                  that.d1 << that.d2 << that.d3 << that.d4;
    }
};

With the main program:

int main(int argc, char *argv[])
{
    mat4<type> mat1(1, 0, 0, 0,
                    0, 1, 0, 0,
                    0, 0, 1, 0,
                    0, 0, 0, 1);

    std::cout << mat1 << std::endl;

    mat4<type> mat2();

    std::cout << mat2 << std::endl;

    mat4<type> mat3;

    std::cout << mat3 << std::endl;

    return 0;
}

Now, mat1 and mat3 are instantiated correctly, but mat2 behaves stangely. Presumably it's a trivial problem but I'm just failing pretty hard. The ouput produced follows:

at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at mat4 consctructor
[0001.00][0000.00][0000.00][0000.00]
[0000.00][0001.00][0000.00][0000.00]
[0000.00][0000.00][0001.00][0000.00]
[0000.00][0000.00][0000.00][0001.00]
1
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at type constructor
at mat4 consctructor
[0000.00][0000.00][0000.00][0000.00]
[0000.00][0000.00][0000.00][0000.00]
[0000.00][0000.00][0000.00][0000.00]
[0000.00][0000.00][0000.00][0000.00]

As you see, mat1 and mat3 output nicely, while mat2's output is 1. Why?

Am I instantiating the object correctly? What's the proper way of initializing the object in automatic memory? I understand this is important for scope-based resource management...

I've beginner level C++ skills and you'll probably spot the mistake very quickly. I'd just like to understand what I'm doing wrong and why. Thanks in advance for the attention.

DVNO
  • 163
  • 2
  • 6
  • 4
    the problem is actually not related to templates, but whenever you write `T t();` this will not create an object of type `T` called `t`. Instead it declares a function taking zero parameters returning a `T` – 463035818_is_not_an_ai Mar 24 '16 at 13:03
  • 1
    The simple solution is now `T t{};` (curly braces) which cannot be mistaken for a function declaration. – MSalters Mar 24 '16 at 13:08
  • I see the confusion... Thank you so much for the quick response! Also for letting me know this was a dupe. I really hadn't found anything close to what I wanted, was probably using bad search terms, I guess... – DVNO Mar 24 '16 at 14:53

1 Answers1

5

If you enable compile warnings, you get:

main.cpp:59:20: warning: empty parentheses interpreted as a function declaration [-Wvexing-parse]
    mat4<type> mat2();
                   ^~
main.cpp:59:20: note: remove parentheses to declare a variable
    mat4<type> mat2();
                   ^~
main.cpp:61:18: warning: address of function 'mat2' will always evaluate to 'true' [-Wpointer-bool-conversion]
    std::cout << mat2 << std::endl;
              ~~ ^~~~

Which pretty much explains everything, except that true is converted to 1 when outputting it, which is why you got 1.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • I understand. Will remember to compile using warning flags from now on! Thank you for the quick response... – DVNO Mar 24 '16 at 14:51