CC cannot instantiate template class static variable
Hi,
Is the following valid C++ code?
$ cat smember.h
template<typename T>
class TC
{
public:
static const unsigned sSize;
static const char* sName;
};
$ cat smember.cc
#include "smember.h"
namespace { int unused; }
$ cat smain.cc
#include <iostream>
#include "smember.h"
class X {};
template<> const unsigned TC<X>::sSize = sizeof(TC<X>);
template<> const char* TC<X>::sName = "TC<X>";
int main()
{
std::cout << TC<X>::sName << ":" << TC<X>::sSize << "\n";
}
$ CC -verbose=template smain.cc
"/net/lmgtds01/sw/SUNWspro11/SUNWspro/prod/include/CC/Cstd/./ostream", line 471: Information: Library has instance std::operator<<(std::ostream &, const char*).
"/net/lmgtds01/sw/SUNWspro11/SUNWspro/prod/include/CC/Cstd/./iosfwd", line 143: Information: Library has instance std::ostream::operator<<(unsigned).
Information: Unable to instantiate TC<X>::sName.
"smember.cc", line 3: Error: Multiple declaration for unused.
"smain.cc", line 11: Information: Unable to instantiate TC<X>::sSize.
1 Error(s) detected.
$ CC -V
CC: Sun C++ 5.8 2005/10/13
For some reason, CC thinks it cannot instantiate TC<X>::sName and TC<X>::sSize, and it automatically includes smember.cc in the compilation process, hence the multiple declaration error.
If I delete (or rename) smember.cc, I can compile and link smain.cc into a.out and it runs fine. Is this a bug of the CC compiler?
I know that "-template=no%extdef" can prevent CC searching for template definition in other cpp files. But I am using stlport4 library ("-library=stlport4"), and it seems that stlport4 library cannot be compiled with "-template=no%extdef".
Regards,
huoq
[1957 byte] By [
huoq] at [2007-11-26 10:54:59]

# 1
I think you answered your own question.
If a .h file contains template declarations, the compiler automatically includes a corresponding .cc (or .c, .C, .cpp, .cxx) file. Therefore, the corresponding .cc file can contain definitions for templates declared in the .h file, but NOTHING else. The .cc file is never compiled by itself, because it is automatically included in other compilations.
In current release, both stlport and libCstd depend on the automatic inclusion. In future releases we will provide a way to use-template=no%extdef and still use the system libraries.
# 2
The problem is that we are using the template include model. We compile every c++ source file explicitly, and these c++ files are not written in the header file style.
I would like to find a way to prevent the compiler from automatic template definition searching. The approach I am taking is to include all necessary template definitions in the translatation unit.
But, I do not know how to handle this static member initialization case. Are there anything I can include in the header file to satisfy the compiler? I cannot think of anything. After all, the program compiles and runs fine of smemnber.cc does not exist.
Regards,
huoq
huoq at 2007-7-7 3:08:06 >

# 3
Your only problem is due to automatic file inclusion, right?
You just need to rename and/or reorganize some files.
In your example, smember.cc is unrelated to smember.h, so rename smember.cc to something else.
In the real application, if smember.cc includes some definitions for templates declared in smember.h, move those definitions into smember.h.
I think that solves your problem.
# 4
We have thousands of source and header files. Almost all of them are in .h and .cpp pairs. They compile fine on Windows and Linux. Changing of the filenames is not an easy option.
In the real application, smember.h contains several normal classes and template classes, and the definition of template classes. smember.cpp contains the definition of normal classes.
My question is what information the compiler is searching in the offending cpp file, considering the victim cpp file compiles fine if the offending cpp file does not exist. I know it's related to the static member of template class, as indicated by the information given by "-verbose=template". But what is it? You have not answered this question.
huoq at 2007-7-7 3:08:06 >

# 5
If a template is declared but not defined in foo.h, the compiler automatically includes foo.cc if it needs to instantiate the template. If none of the template declarations lacking definitions are needed, foo.cc will not be included. "Needed" is a somewhat fuzzy concept, however.
In the example code, static member sSize of template TC is needed, the definition is not visible, so the compiler includes smember.cc. Same for member sName.
The informational messages "cannot instantiate" are bogus. The compiler needs an instantiation of TC<X>::sSize and sName, but not does need to generate them from the primary template because of the explicit specializations. The compiler ought to say "instantiation not needed," or say nothing.
In principle, the compiler might be able to figure out that smember.cc in this example does not actually need to be included, since the required instances are already present. But the compiler is not organized that way. It collects all the template declarations that are available, then chooses the best match. In the general case, the compiler must behave that way to get the best match or determine that there is no best match.