Problem with basic templates on GCC

W

Winbatch

Hi,
If this should be directed to another group, please let me know...
I've been working with templates for a few weeks and have been able to
develop some nice code on solaris using the Forte C++ compiler (version 7).
However, nothing related to templates seems to be compiling correctly when I
use g++ on netbsd. I can't tell if it is either: a problem with my code, a
problem with NetBSD, or a problem with GCC. I have tried to create the
most basic of tests to illustrate the problem. Could someone tell me why
this compiles and runs fine using the Forte compiler but does not with g++?

MyTemp.h
--------------------------
#include <iostream>
template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};
MyTemp.cpp
----------------------------------------
#include "MyTemp.h"

template<class T> MyTemp<T>::MyTemp( T temp1 )
{
temp = temp1;
}
template<class T> void MyTemp<T>::print()
{
cout<<temp;
}

Test.cpp
------------------------------------------
#include <unistd.h>
#include <iostream>
#include <string>
#include <MyTemp.h>
using namespace std;
int main()
{
cout<<"In Test"<<endl;
MyTemp<string> mt("TEST");
mt.print();
return 0;
}

------------------------------------------------------
g++ -c -I./ -g -D_DEBUG -Wall -Wno-parentheses -c *.cpp
g++ *.o -o Test
/usr/lib/libstdc++.so: warning: reference to compatibility vfork(); include
<unistd.h> for correct reference
Test.o: In function `main':
/arpa/ag/d//Test/Test.cpp:7: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::MyTemp(basic_string<char,
string_char_traits<char>, __default_alloc_template<false, 0> >)'
/arpa/ag/d//Test/Test.cpp:7: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::MyTemp(basic_string<char,
string_char_traits<char>, __default_alloc_template<false, 0> >)'
/arpa/ag/d//Test/Test.cpp:8: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::print(void)'
/arpa/ag/d//Test/Test.cpp:8: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::print(void)'
*** Error code 1

Stop.
 
I

Ioannis Vranos

Winbatch said:
Hi,
If this should be directed to another group, please let me know...
I've been working with templates for a few weeks and have been able to
develop some nice code on solaris using the Forte C++ compiler (version 7).
However, nothing related to templates seems to be compiling correctly when I
use g++ on netbsd. I can't tell if it is either: a problem with my code, a
problem with NetBSD, or a problem with GCC. I have tried to create the
most basic of tests to illustrate the problem. Could someone tell me why
this compiles and runs fine using the Forte compiler but does not with g++?

MyTemp.h
--------------------------
#include <iostream>
template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};
MyTemp.cpp
----------------------------------------
#include "MyTemp.h"

template<class T> MyTemp<T>::MyTemp( T temp1 )
{
temp = temp1;
}
template<class T> void MyTemp<T>::print()
{
std::cout<<temp;

}

Test.cpp
------------------------------------------


// What's this? #include said:
#include <iostream>
#include <string>
#include <MyTemp.h>
using namespace std;
int main()
{
cout<<"In Test"<<endl;
MyTemp<string> mt("TEST");
mt.print();
return 0;
}

------------------------------------------------------
g++ -c -I./ -g -D_DEBUG -Wall -Wno-parentheses -c *.cpp
g++ *.o -o Test
/usr/lib/libstdc++.so: warning: reference to compatibility vfork(); include
<unistd.h> for correct reference
Test.o: In function `main':
/arpa/ag/d//Test/Test.cpp:7: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::MyTemp(basic_string<char,
string_char_traits<char>, __default_alloc_template<false, 0> >)'
/arpa/ag/d//Test/Test.cpp:7: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::MyTemp(basic_string<char,
string_char_traits<char>, __default_alloc_template<false, 0> >)'
/arpa/ag/d//Test/Test.cpp:8: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::print(void)'
/arpa/ag/d//Test/Test.cpp:8: undefined reference to
`MyTemp<basic_string<char, string_char_traits<char>,
__default_alloc_template<false, 0> > >::print(void)'
*** Error code 1



It compiles fine here with g++ 3.4.2. Which version are you using? My
exact code:


#include <iostream>
#include <string>


template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};


template<class T> MyTemp<T>::MyTemp( T temp1 )
{
temp = temp1;
}
template<class T> void MyTemp<T>::print()
{
std::cout<<temp;
}


int main()
{
using namespace std;
cout<<"In Test"<<endl;
MyTemp<string> mt("TEST");
mt.print();
return 0;
}
 
W

Winbatch

HappyHippy said:
The problem is that at the point of instantiation (MyTemp<string>
mt("TEST");, Test.cpp) compiler sees only declaration of template class
member functions (from MyTemp.h file) and no their definitions.
You should #include MyTemp.cpp into Test.cpp file. Because for template
classes definions (not only declarations) of all members must be visible
at the point of instantiation.
So you should change
#include <MyTemp.h>
to
#include "MyTemp.cpp"
in Test.cpp file.

But #include 'ing cpp file looks ugly.
I would advise you to rewrite your code as follows:

MyTemp.h
--------------------------
#include <iostream>
#include "MyTemp.hpp"

template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};

MyTemp.hpp hpp is commonly used extension for templates
implementation files
----------------------------------------
template<class T> MyTemp<T>::MyTemp( T temp1 )
{
temp = temp1;
}
template<class T> void MyTemp<T>::print()
{
cout<<temp;
}

Test.cpp
------------------------------------------
#include <unistd.h>
#include <iostream>
#include <string>
#include "MyTemp.h"
using namespace std;
int main()
{
cout<<"In Test"<<endl;
MyTemp<string> mt("TEST");
mt.print();
return 0;
}

There is a VERY GOOD book on C++ templates "C++ Templates: The Complete
Guide" by David Vandevoorde, Nicolai M. Josuttis, ISBN : 0-201-73484-2

Good Luck,
HappyHippy
HH,
Thanks, I will try it. Why would it work in some versions of gcc (as
reported by Ioannis), but not by others? Did it later become part of the
standard?
 
H

HappyHippy

The problem is that at the point of instantiation (MyTemp<string>
mt("TEST");, Test.cpp) compiler sees only declaration of template class
member functions (from MyTemp.h file) and no their definitions.
You should #include MyTemp.cpp into Test.cpp file. Because for template
classes definions (not only declarations) of all members must be visible at
the point of instantiation.
So you should change
#include <MyTemp.h>
to
#include "MyTemp.cpp"
in Test.cpp file.

But #include 'ing cpp file looks ugly.
I would advise you to rewrite your code as follows:

MyTemp.h
--------------------------
#include <iostream>
#include "MyTemp.hpp"

template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};

MyTemp.hpp hpp is commonly used extension for templates
implementation files
----------------------------------------
template<class T> MyTemp<T>::MyTemp( T temp1 )
{
temp = temp1;
}
template<class T> void MyTemp<T>::print()
{
cout<<temp;
}

Test.cpp
------------------------------------------
#include <unistd.h>
#include <iostream>
#include <string>
#include "MyTemp.h"
using namespace std;
int main()
{
cout<<"In Test"<<endl;
MyTemp<string> mt("TEST");
mt.print();
return 0;
}

There is a VERY GOOD book on C++ templates "C++ Templates: The Complete
Guide" by David Vandevoorde, Nicolai M. Josuttis, ISBN : 0-201-73484-2

Good Luck,
HappyHippy
 
W

Winbatch

Ioannis Vranos said:
It compiles fine here with g++ 3.4.2. Which version are you using? My
exact code:


#include <iostream>
#include <string>


template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};


template<class T> MyTemp<T>::MyTemp( T temp1 )
{
temp = temp1;
}
template<class T> void MyTemp<T>::print()
{
std::cout<<temp;
}


int main()
{
using namespace std;
cout<<"In Test"<<endl;
MyTemp<string> mt("TEST");
mt.print();
return 0;
}

Ioannis,
Can you provide the compile command you used?
 
W

Winbatch

HH,

Your sample indicates that I should include the .hpp from the .h. Is that
right? Wouldn't the class need to be defined before the implemenation? (ie
shouldn't the .hpp include the .h instead?)

Winbatch
 
W

Winbatch

Artie Gold said:
There's your problem. Upgrade to a more recent version if you can (2.95
had some problems with template code).

HTH,
--ag

I thought I was seriously going nuts here. Unfortunately, it's not my
machine so I don't have much control. What do you think of the .hpp route
mentioned previously? I'm trying to implement it on that machine..
 
W

Winbatch

HH,

Just wanted to thank you - your suggestion to use the .hpp's not only helped
me to successfully compile on GCC 2.95 on NetBSD, but also on AIX 5.1 using
/usr/vacpp/bin/xlC. (Something I was struggling to accomplish as well).

Thanks again,
Winbatch
 
A

Artie Gold

Winbatch said:
HH,

Just wanted to thank you - your suggestion to use the .hpp's not only helped
me to successfully compile on GCC 2.95 on NetBSD, but also on AIX 5.1 using
/usr/vacpp/bin/xlC. (Something I was struggling to accomplish as well).

Thanks again,
Winbatch
I missed the call before.

However, one point to be made is that as (virtually -- there's Comeau
and something else I believe) no one supports `export', there seems to
be limited utility in separating the templated class definition from its
templated member functions.[1] Where one needs to be visible, at least
some subset of the rest would need to be visible too.

Think of templates as a away of telling the compiler to generate code
for you on demand -- not as code itself. The definitions need to be
visible in any translation unit that use them.

HTH,
--ag

[1] Well, when we're dealing with small projects anyway; even in large
projects any underlying file structure should be transparent to its
clients. `#include'-ing a single `.h' file should be sufficient.
 
I

Ioannis Vranos

Winbatch said:
Ioannis,
Can you provide the compile command you used?


#include <iostream>
#include <string>


template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};


template<class T> MyTemp<T>::MyTemp( T temp1 )
{
temp = temp1;
}
template<class T> void MyTemp<T>::print()
{
std::cout<<temp;
}


int main()
{
using namespace std;
cout<<"In Test"<<endl;
MyTemp<string> mt("TEST");
mt.print();
return 0;
}



C:\c>g++ temp.cpp -o temp.exe

C:\c>temp
In Test
TEST
C:\c>g++ -v
Reading specs from C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/specs
Configured with: ../gcc/configure --with-gcc --with-gnu-ld --with-gnu-as
--host=
mingw32 --target=mingw32 --prefix=/mingw --enable-threads --disable-nls
--enable
-languages=c,c++,f77,ada,objc,java --disable-win32-registry
--disable-shared --e
nable-sjlj-exceptions --enable-libgcj --disable-java-awt --without-x
--enable-ja
va-gc=boehm --disable-libgcj-debug --enable-interpreter
--enable-hash-synchroniz
ation --enable-libstdcxx-debug
Thread model: win32
gcc version 3.4.2 (mingw-special)

C:\c>
 
H

HappyHippy

Yes you are completely right.
Sorry.
It should look like this:

MyTemp.h
--------------------------
#include <iostream>

template <class T> class MyTemp
{
private:
T temp;

public:
MyTemp (T temp1);
void print();


};

#include "MyTemp.hpp"
 
H

HappyHippy

There is a way to make it work without #include 'ing implementation to
declaration. Keyword "export" should be used for this purpose according to
the standard. BUT. Neither VC++ 7.1 nor gcc 3.3.x implement this feature as
far as I know.

It works in Ioannis' example because (as I understood from his post) he put
everything in a single file. So it is almost the same as using #include
which I suggested to use.

Regards,
HappyHippy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top