# About C++ Templates

When you get to server.cpp in Tutorial 2 you'll see these lines at the bottom:

    #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
    template class ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR>;
    template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>;
    #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
    #pragma instantiate ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR>
    #pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
    #endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
    Thanks to Krishna Padmasola for providing these.

What's that all about?

Well, if you've been doing ACE for more than about 30 seconds you will have run into the joys and sorrows of C++ templates. They're really great things that prevent the need for complex #define'd macros, ensure type safety and do other really nifty things. One of the problems, however, is that not all compilers can figure out what templates you need.

Take the simple templated class:

    template <class DATATYPE>
    class MyTemplate
    {
    public:
        MyTemplate(void)
            {
            }

        DATATYPE data(void)
            {
                return data_;
            }

        void data( DATATYPE _data )
            {
                data_ = _data;
            }

    protected:

        DATATYPE data_;
    };

Now suppose you write the following code fragment:

    int main(int,char**)
    {
        MyTemplate<int> itemp;
        MyTemplate<char> ctemp;

        ...
    }

Some compilers will take care of you and automatically generate the equivalent classes:

    class MyTemplate
    {
    public:
        MyTemplate(void)
            {
            }

        int data(void)
            {
                return data_;
            }

        void data( int _data )
            {
                data_ = _data;
            }

    protected:

        int data_;
    };

    class MyTemplate
    {
    public:
        MyTemplate(void)
            {
            }

        char data(void)
            {
                return data_;
            }

        void data( char _data )
            {
                data_ = _data;
            }

    protected:

        char data_;
    };

On the other hand, some compilers will complain loudly about undefined symbols and all sorts of other things. When Clinton Carr compiled server.cpp of Tutorial 2 on his RedHat 5.1 (gcc) system, for instance, he was rewarded with these lovely errors:

    server.cpp:60: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::ACE_Acceptor(ACE_Reactor *)'
    server.cpp:72: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::open(ACE_INET_Addr const &, ACE_Reactor *,int)'
    server.cpp:73: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::~ACE_Acceptor(void)'
    server.cpp:112: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::~ACE_Acceptor(void)'

Figuring out the correct manual instantiations is usually an iterative and tedious process. On Linux, I generally use a version of gcc that will do automatic instantiaion. "Normal" gcc with the Cygnus repo patches does that as does egcs. Lately (1/99) I've been using egcs 1.1.1 with pretty good results. On our Digital Unix 4.0b system the native compiler (CXX) has switches that will request it to also automatically instantiate templates as needed.

The tradeoffs?

If you choose to do manual instantiation then your code will work just about anywhere ACE will. For complex applications, it can take a number of hours to get things right.

If you choose to let the compiler do instantiations for you then it will perform the iterative process. That means that every compile will be longer than without manual instantiations.

Compromise?

Yes, you can do that. You can manually instantiate some templates and let the compiler get the rest. Some compilers will generate output that you can then use to figure out the correct templates. Gcc/egcs create .rpo files for each object. These files contain mangled names that the compiler uses to figure out what to instantiate. With c++filt and some patience, you can parse that stuff to figure out what the compiler is instantiating for you. Note that c++filt expects you to have a GNU-flavored C++ compiler available.

My best advice is to get a compiler that will handle the instantiations for you. When you have some free time on your hands, take a look at its intermediate files (if any) and start working on manual instantiation.

For some more hints, take a look at ACE-INSTALL

Thanks to Amos Shapira for catching a number of errors here.