Thread: Please help with C++ templates - going through the tutorials

  1. #1
    Registered User
    Join Date
    Oct 2012
    Posts
    11

    Please help with C++ templates - going through the tutorials

    Hello guys.

    A couple of quick questions. First one, I'd rather not post using my real name, but if I login without Facebook, I can't start a thread. What's the secret?

    Secondly, I'm a PHP and JavaScript programmer (experienced with OO), I'm just going through the nice C++ tutorials on this site and doing some experimentation.

    I've got to the Templates tutorial:

    Template Classes in C++ - Cprogramming.com

    But now I'm stuck. I even copied and pasted the code snippets provided from that tutorial into my files, and the compiler still complains. The output I'm getting is this (it's a similar error if I just copy & paste the snippets, but below is "my own" version of the code).

    I'm using Code::Blocks and the default compiler setup that comes with that IDE.

    Code:
    obj\Debug\main.o||In function `main':|
    C:\stuff\vics\experiment\TemplateExperiment\TemplateExperiment\main.cpp|11|undefined reference to `Multiplier<int>::multiply(int, int)'|
    ||=== Build finished: 1 errors, 0 warnings ===|
    
    Below are the three files I'm using:

    main.cpp:
    Code:
    include <iostream>
    #include "Multiplier.h"
    
    
    using namespace std;
    
    
    int main()
    {
        int num1 = 5;
        int num2 = 10;
        Multiplier <int> multiplier;
        int result = multiplier.multiply( num1, num2 );
        cout << result << "\n\n";
    }

    Multiplier.h
    Code:
    #ifndef MULTIPLIER_H
    #define MULTIPLIER_H
    
    
    
    
    template <class Type> class Multiplier
    {
        public:
            Type multiply(Type firstNumber, Type secondNumber);
        protected:
        private:
    };
    
    
    #endif // MULTIPLIER_H


    Multiplier.cpp
    Code:
    #include "Multiplier.h"
    
    
    /*
    Multiplier::Multiplier()
    {
        // Constructor
    }
    
    
    
    
    template <class Type> Type Multiplier<Type>::Multiplier()
    {
        // Constructor
    }
    */
    
    
    template <class Type> Type Multiplier<Type>::multiply( Type firstNumber, Type secondNumber)
    {
        return firstNumber * secondNumber;
    }
    Last edited by Vic Webster Jnr; 11-01-2012 at 02:32 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2012
    Posts
    11
    Thanks. I haven't tried it yet (I don't have the code, IDE, etc. setup on this computer).

    Assuming that it fixes the problem, what's the cause? Is this a fault of the compiler? Seems sort of like a "hack" to me, but what would I know?

    Cheers.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Vic Webster Jnr
    Assuming that it fixes the problem, what's the cause? Is this a fault of the compiler? Seems sort of like a "hack" to me, but what would I know?
    When a compiler compiles Multiplier.cpp, unless it has somehow already seen that Multiplier <int> will be used, it would not be able to determine what code to generate. Should it generate code for Multiplier<double> too? So, this is not really the fault of the compiler. Maybe it is the fault of C++ for not having a module system that can simplify this.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    A couple of quick questions. First one, I'd rather not post using my real name, but if I login without Facebook, I can't start a thread. What's the secret?
    Did you register? There is no posting milestone to pass before you can start a thread.

  6. #6
    Registered User
    Join Date
    Oct 2012
    Posts
    11
    Quote Originally Posted by whiteflags View Post
    Did you register? There is no posting milestone to pass before you can start a thread.
    Yeah, I did. It appears the account has just yet to be approved.

  7. #7
    Registered User
    Join Date
    Oct 2012
    Posts
    11
    Quote Originally Posted by laserlight View Post
    When a compiler compiles Multiplier.cpp, unless it has somehow already seen that Multiplier <int> will be used, it would not be able to determine what code to generate. Should it generate code for Multiplier<double> too? So, this is not really the fault of the compiler. Maybe it is the fault of C++ for not having a module system that can simplify this.
    Thankyou. That helps me to understand.

    However, now I have more questions.

    I tried it out - and a few other solutions - and they do work.

    One of them is to simply #include Multiplier.cpp in the main.cpp file, instead of including Multiplier.h.

    The Multiplier.cpp #includes Multiplier.h, so everything works.

    This strikes me as a much more logical way to arrange your files. The main program includes the .cpp files that it needs, and they include their own headers.

    Obviously I'm a complete newb to C++. There must be some reason that C++ programs include only the header file, and not the main program as I described above. Why is this?

    P.S. oddly (for me anyway), if I do it the reverse, and #include Multiplier.h in main.cpp, and then #include Multiplier.cpp underneath the class definition in multiplier.h, that doesn't work. To my limited understanding it's doing exactly the same thing as above, just in a slightly different way. In fact, if I just cut & paste the code from Multiplier.cpp into Mutliplier.h instead of using an include directive, that does work. Can anyone explain why it doesn't work that way? I am assuming that it's because #include statements are only allowed at the top of the file ... ?

    Sorry to ask annoying newb questions.
    Last edited by Vic Webster Jnr; 11-01-2012 at 04:52 PM.

  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    One of them is to simply #include Multiplier.cpp in the main.cpp file, instead of including Multiplier.h.
    What you have there is the wrongest of wrong minded approaches.

    If I include "Multiplier.h" and "Multiplier.h" provides templates facilities I expect to be granted access to those facilities precisely because that is exactly what headers do in the C and C++ languages.

    If you must keep the declaration and definition of template facilities separate please do so by including the relevant ".cpp" or whatever in the header so that I as a client do not need to know about this arrangement.

    There must be some reason that C++ programs include only the header file, and not the main program as I described above.
    I'm not even sure what you asking.

    Can anyone explain why it doesn't work that way?
    We could if we knew what your were doing.

    I am assuming that it's because #include statements are only allowed at the top of the file ... ?
    I assure you that this is wrong. Whatever your problem, that isn't it.

    Soma

  9. #9
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    This strikes me as a much more logical way to arrange your files. The main program includes the .cpp files that it needs, and they include their own headers.

    Obviously I'm a complete newb to C++. There must be some reason that C++ programs include only the header file, and not the main program as I described above. Why is this?
    Have you looked at the compile and link phase of development at all? It's pretty important information.

    Header files are supposed to be compiled once.
    Source files are definitely compiled once.

    Turning source files into header files by including them doesn't really buy you anything. It just turns your source files into header files. Consider this, that header files recompile when they are edited, and so too are source files that depend on them. The easiest way to explain why this is the wrong mindset is by projecting the worst case scenario. You are essentially volunteering to recompile the entire program's code every single time.

    In C++ we are not supposed to care what gets compiled first, or in what order everything is compiled before linking. That is why you sprinkle #includes all over the source files in the project so that you definitely have access to what you need. If you don't then you are taking a guess that herp.cpp which #includes stuff is compiled before derp.cpp, and you have 0 guarantees that this is the case.

    But the worst part about it is really that you don't have the benefit of a fast compile. Fixing a game breaking bug that affects a small portion of the code and recompiling only that code in the time it takes is supposed to be a boon.



    The reason that templates are usually in header files is because they are just really fancy declarations (I can hear the boos in the crowd). The purpose of templates is to quickly generate code in the compilation phase. This is cool for a lot of code that is supposed to be similar (like how all arrays work the same) but can be specifically different (like how all arrays work the same, but Array<double> and Array<Foo> are different types, but you need both). It is a time saving measure in the implementation phase of development. [edit] And unless you know with certainty where such code is needed, it is easiest to put templates in a header file, where they can be anywhere. [/edit]
    Last edited by whiteflags; 11-01-2012 at 10:05 PM. Reason: minor spelling things

  10. #10
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I can hear the boos in the crowd.
    Indeed.

    I find the word "template" to be very suitable to describe templates which are templates.

    It is a time saving measure in the implementation phase of development.
    ^_^

    Proof, ladies and gentleman, that whiteflags never works with "Boost::Proto".

    Soma

  11. #11
    Registered User
    Join Date
    Oct 2012
    Posts
    11
    Thanks very much everyone for taking the time to provide such long responses. It's very helpful. I'm just starting and haven't had the opportunity to study these things in depth.

    For now, I have another question. If you compile and run the code, it should be obvious enough. The problem is that the "sizeof" the array inside the template function reads as "4". However the same code, copied and pasted in the main function, gives the expected output of "45". If someone could explain this to me, I'd be most appreciative. Thanks very much again for all your help.

    Code:
    #include "ArrayExperiments.h"
    #include <iostream>
    
    
    using namespace std;
    
    
    ArrayExperiment::ArrayExperiment()
    {
        cout << "\n\n";
        cout << "Experiments with arrays" << endl;
        cout << "-----------------------" << endl;
    
    
        char abcArray[5] = { 'a', 'b', 'c', 'd', 'e'};
        this->printArray( abcArray );
    
    
        int sizeOfArrayTotal = sizeof(abcArray);
        int sizeOfOneSlot    = sizeof(abcArray[0]);
        cout << sizeOfArrayTotal << " / " << sizeOfOneSlot << " = " << (sizeOfArrayTotal/sizeOfOneSlot) << endl;
    
    
    }
    
    
    
    
    
    
    template <typename Type> void ArrayExperiment::printArray( Type myArray[] )
    {
        short length = this->getSize(myArray);
        cout << length;
    }
    
    
    
    
    
    
    inline template <typename Type> int ArrayExperiment::getSize( Type myArray[] )
    {
        cout << "Checking first value ... " << myArray[0] << endl;
        int sizeOfArrayTotal = sizeof(myArray);
        int sizeOfOneSlot    = sizeof(myArray[0]);
        cout << sizeOfArrayTotal << " / " << sizeOfOneSlot << " = " << (sizeOfArrayTotal/sizeOfOneSlot) << endl;
        return sizeof( myArray ) / sizeof( myArray[0] );
    }

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The array was converted to a pointer to its first element, and indeed myArray in the printArray template function is a pointer, not an array. One solution it to have two parameters instead: an iterator to the beginning of a range, and an iterator one past the end of the range. Thus, the entire range of the array can be "passed". Another solution is to use std::array instead. Yet another solution is just to pass the size as an argument.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    There are better solutions if you want the convenience of the implied size from arrays.

    Soma

    trouble with hash function implementing

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Tutorials
    By polonyman in forum Windows Programming
    Replies: 6
    Last Post: 09-14-2004, 11:10 AM
  2. plz help - CP.com Tutorials
    By polonyman in forum C++ Programming
    Replies: 5
    Last Post: 09-09-2004, 03:33 PM
  3. SDL tutorials???
    By Ace Bowers in forum Game Programming
    Replies: 8
    Last Post: 07-19-2003, 10:16 AM
  4. Tutorials
    By Chr1s in forum C++ Programming
    Replies: 3
    Last Post: 02-17-2002, 12:10 PM
  5. Tell me tutorials
    By Unregistered in forum Game Programming
    Replies: 0
    Last Post: 01-09-2002, 03:33 AM