LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   C++ template blues (https://www.linuxquestions.org/questions/programming-9/c-template-blues-452592/)

spursrule 06-07-2006 08:34 PM

C++ template blues
 
It's been a while since I've programmed for school, and after picking up a copy of Sedgewick I decided to try out one of the problems for kicks. The class I wrote works great for concrete types, but when I tried to make a templated version I couldn't get it to link, as it couldn't resolve function calls to the templated class. Here's a stripped down version of the example.

Here's the makefile:

Code:

exe=polyadd
obj=polyadd.o polynomial.o

$(exe): $(obj)
        c++ $(LDFLAGS) -o $(exe) $(obj)
       
polynomial.o: polyadd.c++ polynomial.c++
        c++ $(CXXFLAGS) -c polynomial.c++

polyadd.o: polyadd.c++ polynomial.h
        c++ $(CXXFLAGS) -c polyadd.c++

clean:
        -rm -f $(obj) $(exe)

Here's the file err.fuck after running the command make 2>err.fuck
Code:

polyadd.o: In function `main':
polyadd.c++:(.text+0x124): undefined reference to `polynomial<int>::polynomial(std::vector<int, std::allocator<int> >&)'
polyadd.c++:(.text+0x137): undefined reference to `polynomial<int>::print(std::basic_ostream<char, std::char_traits<char> >&) const'
collect2: ld returned 1 exit status
make: *** [polyadd] Error 1

And here's the code:

Code:

/** polynomial.h */
#ifndef        POLYNOMIAL_H
#define        POLYNOMIAL_H


#include        <vector>
        using        std::vector;
#include        <ostream>
        using        std::ostream;

       
template <class T>
class
polynomial
{
        public:
                T&        get_component (int n) const;
                int        degree () const;
                polynomial (vector<T> &);
                void        print (ostream &) const;
        private:
                vector<T>        p;
};

#endif

Code:

/** polynomial.c++ */
polynomial<T>::polynomial (vector<T> &v)
{
        p = v;
}


template <class T>
T&
polynomial<T>::get_component (int n) const
{
        return        p [n];
}


template <class T>
int
polynomial<T>::degree () const
{
        return        p.size ()-1;
}


template <class T>
void
polynomial<T>::print (ostream &os) const
{
        if (p.size ()==0)
                return;
        else if (p.size ()==1)
                os << p[0];
        else {
                os << p[0] << " + ";

                for (int i=1; i < degree (); i++)
                        os << p[i] << "x^" << i << " + ";
                os << p [degree ()] << "x^" << degree ();
        }
}


Code:

/** polyadd.c++ */

#include        <iostream>
        using        std::cout;
        using        std::endl;
        using        std::cerr;
#include        "polynomial.h"
#include        <vector>
        using        std::vector;



int
main (int argc, char *argv [])
{
        vector<int>        v;
        v.push_back (1);
        v.push_back (2);
        v.push_back (3);
        v.push_back (4);        // 1 + 2x + 3x^2 + 4x^3

        for (int i=0; i<v.size (); i++)
                cout << v[i] << " ";
        cout << endl;
       
        polynomial<int>        p(v);

        p.print (cout);

        return        0;
}

Please tell me I'm just doing something stupid. I remember doing stuff like this in Visual C++ for my class. I've tried it under gcc-4.0.3 and gcc-3.3.6, and the output I posted is from compiling with gcc-4.0.3.

Thanks

graemef 06-07-2006 08:55 PM

See this thread. In short you need to have the definition and declaration of your template functions in the same file

spursrule 06-07-2006 09:20 PM

so it's a g++ bug :(

taylor_venable 06-07-2006 09:34 PM

Quote:

Originally Posted by spursrule
so it's a g++ bug :(

No, not quite. Stroustrup mentions this problem in "The C++ Programming Language" (I did some more research after I solved my problem): he says that if you want to separate your template declarations and definitions, use the "export" keyword in front of the definition. However, that doesn't really change how you have to write the code, because GCC does not support the "export" keyword yet. Apparently, it's very hard to get to work correctly, probably for the reasons that graemef mentions in that other thread. So GCC actually handles the template correctly, but unfortunately does not correctly handle the mechanism used to make up for the shortcoming in the language. So yeah, you have to put them both in the same file, but it's not (at least not immediately) GCC's fault.

spursrule 06-07-2006 09:48 PM

Wow... that's hard to believe, since my copy of Strousstrup is 9 years old and mentions exactly that in chapter 13. Does Intel's C++ compiler handle templates correctly?

taylor_venable 06-08-2006 08:39 AM

According to the Wikipedia article on C++ only two compilers have ever supported the export keyword, Comeau C++ (never heard of that one myself) and a version of Borland C++ Builder. This InformIT article (although marked as "outdated") notes that in practice the export feature actually doesn't do what it sounds like, because the real meat of the template is in the implementation, not the prototype. Taken all together, it sounds like this feature was simply too much for existing compiler technology to cope with.


All times are GMT -5. The time now is 04:52 PM.