Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Pretty much everybody who has ever tried to write a non-trivial template library met the problem of organizing template source code. Led by inertia, many C++ programmers try to organize template code the same way they did it with non-template code: declarations in header files, and definitions in CPP files. This attempt leads to linker errors when the point of instantiation is reached. For instance:

// swap.h

template <typename T> void swap (T& left, T& right);

//swap.cpp

template <typename T> void swap (T& left, T& right)
    {
    T temp = left;
    left = right;
    right = temp;
    }

// main.cpp

#include "swap.h"

int main()
    {
    int a = 1, b = 2;
    swap(a, b);
    }

will result in:

main.obj : error LNK2019: unresolved external symbol 
  "void __cdecl swap<int>(int &,int &)" (??$swap@H@@YAXAAH0@Z) 
  referenced in function _main
Debug/Nonstandardvc71.exe : fatal error LNK1120: 1 unresolved externals

with MSVC 7.1.

Generally, there are two ways to organize template source code[1]:

  1. Inclusion model, where template definitions are included in every translation unit in which they are implicitly or explicitly instantiated.
  2. Separation model, in which at the point of instantiation, only template declarations are included, and definitions are in a separate translation unit.

The inclusion model is widely used within C++ community. I have written about it in my Code Project article: How to Organize Template Source Code, and I am sure there are also other good on-line resources that cover it. Here, I am going to concentrate on the separation model.

Some Theory Behind Separation Model and export

To use the separation model, we need the keyword export:

// swap.h

export template <typename T> void swap (T& left, T& right);

Function template swap is now considered to be exported, and can be used without its definition being visible [2].

To be exported, a template definition must be in the same translation unit in which it was declared as exported [3]. In practice, it means that export can be added to the definition [1]:

// swap.h

template <typename T> void swap (T& left, T& right);

// swap.cpp

export template <typename T> void swap (T& left, T& right)
    {
    T temp = left;
    left = right;
    right = temp;
    }

// main.cpp

#include "swap.h"

int main()
    {
    int a = 1, b = 2;
    swap(a, b);
    }

to a declaration preceding the definition in the same translation unit:

// swap.h

export template <typename T> void swap (T& left, T& right);

// swap.cpp

template <typename T> void swap (T& left, T& right)
    {
    T temp = left;
    left = right;
    right = temp;
    }

// main.cpp

#include "swap.h"

int main()
    {
    int a = 1, b = 2;
    swap(a, b);
    }

or even to both places, if you feel it improves the readability [2]:

// swap.h

export template <typename T> void swap (T& left, T& right);

// swap.cpp

export template <typename T> void swap (T& left, T& right)
    {
    T temp = left;
    left = right;
    right = temp;
    }

// main.cpp

#include "swap.h"

int main()
    {
    int a = 1, b = 2;
    swap(a, b);
    }

Note that I could not find the samples for the first case (export added directly to the definition, but not to any declaration in header files) either on Comeau website or in the Vandevoorde-Josuttis book [2], and therefore I somewhat suspect this scenario not to be supported in practice. However, Stroustrup explicitly shows this technique in [1] and I could not find anything in the Standard [3] that would prevent it.

In any case, if a template is exported, its definition can be looked up across translation units. It is up to the compiler to ensure that exported definition is found in the point of instantiation.

Strictly speaking, only non-inline function templates, non-inline member function templates, non-inline member functions of class templates, and static data members of class templates can be exported. Class templates cannot be exported; however, export keyword can be added to a class template declaration. This means that all its exportable members defined in that translation unit are exported:

export template<typename T> class C
    {
    public:

        //exported

        void NonInlineMemberFunction();
        static int staticDataMember;
        class MemberClass {};        
        template <typename T2> void NonInlineFuncMemberTemplate();

        // implicitely declared with export

        template <typename T1> class MemberClassTemplate {}; 

        // not exported

        void InlineMemberFunction(){}
        int nonStaticDataMember;
        template <typename T3> void InlineFuncMemberTemplate(){}
    };

Templates defined in an unnamed namespace are not exported [3]. In fact, the next piece of code:

namespace 
    {
    export template <typename T> void f(T value)
        {}
    }

will trigger a compiler error:

3: error: a member of an unnamed namespace cannot be declared "export"

when compiled on the Comeau online compiler.

Problems With export

The main problem with export seems to be that it is a complicated feature to implement. Consequently, today there is only one commercially available compiler that supports it (EDG 3.3 based Comeau 4.3.3), and no indications that any other compiler vendor will include it any time soon. The cost of implementing export seems to be so high that Herb Sutter and Tom Plum officially recommended removing it from the Standard, arguing that wide adoption of export would set C++ back for up to two years [4]. As far as I know, the C++ standard committee voted against this proposal, and export is going to remain a part of standard C++.

Another problem is not really a problem but more an unrealistic expectation. Namely, some developers believe that export would enable them to ship their template libraries without implementation source code, just as with non-template libraries. This belief is unfounded: when a library user instantiates a template, they still need access to the source (or, theoretically speaking, its equivalent in some form) to generate a template specialization. This is a nature of templates, and exporting does not change it. Therefore, even if export was more widely available, it might have disappointed the template libraries writers.

If I am allowed to have any opinion on export, (I have never had a chance to work with a compiler that supports this feature), I would like to see it implemented in Visual C++. Granted, if my job was developing C++ compilers, I would probably hate it, and if I was just a user of template libraries (most of the time I am, actually) I couldn�t care less about it. However, since I occasionally write some template code, I feel that export would help me organize my source in a nicer, more readable and maintainable manner.

Microsoft Visual C++ 7.1 and export

Microsoft Visual C++ 7.1 does not recognize export keyword. The �swap� example gives the following two compiler errors:

error C2143: syntax error : missing ';' before ''template<''
error C2501: 'export' : missing storage-class or type specifiers

Herb Sutter, a Visual C++ architect, in his earlier interviews promised to push for 100% standard conformance, including export. However, it seems that VC++ team has had other priorities lately (C++/CLI). Since export is expensive to implement and there is no big demand for it, I would be surprised to ever see this feature in Microsoft C++ compilers. Of course, this is only my personal opinion � I have never heard such statements from anyone within Microsoft.

Conclusion

Microsoft Visual C++ 7.1 is among the vast majority of C++ compilers that do not support export keyword, and there is no sign it will change in a near future. Most developers will probably never notice lack of export unless they try to write some template code on their own. For template libraries developers, export may have some value, but it is not clear how much at this point, since it has been implemented on only one compiler so far.

References

  1. Bjarne Stroustrup: The C++ Programming Language 3rd edition.
  2. David Vandevoorde, Nicolai M, Josuttis: C++ Templates The Complete Guide, Addison-Wesley 2002.
  3. ISO/IEC 14882 Programming languages - C++, 1998
  4. Herb Sutter, Tom Plum: Why We Can�t Afford Export.
You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralWhere is the problem?
nutty
0:06 1 Oct '04  
Probably I don't really understand the real problem here.

I am using VCPP 7.1 with the separation model. As written above there's need to instanciate a template to be used in another translation unit. A template cannot be exported as a template. That means if I want to export my template class I write
template class MyClass<MyType, MyVal>;
into the *.cpp file and the compiler will instanciate the template member functions and export them as any other member function.

I don't know about non member functions as I rarely use them and never wanted to export one.
But, I would like to know about any limitations to this that anyone knows and I haven't yet discovered. Also if I have misunderstood this completely can someone point me to the actual problem ( other than it is not the way the standard says ).


GeneralRe: Where is the problem?
Nemanja Trifunovic
3:26 1 Oct '04  
nutty wrote: I am using VCPP 7.1 with the separation model.
No, you're not. Smile MSVC++ 7.1 does not support the separation model. What you are describing (if I understand correctly, because your angle brackets cannot be seen) is explicit instantiation, which is just another implementation of inclusion model. Separation model is about making templates visible accross compilation units, not template specializations.


nutty wrote: A template cannot be exported as a template
That's the point. It can if you have export available on your compiler.


My programming blahblahblah blog. If you ever find anything useful here, please let me know to remove it.
GeneralAn alternative approach
Niklas Lindquist
23:15 20 Sep '04  
I have always organized templates in *.h and *.cpp files as any non-template code. The last thing I do in the *.h file is #include "*.cpp". This way, the code is always in the current translation unit, but I can organize it as with non-template code.

Any thoughts on this?
GeneralFinally, a clarification on "export"
Martin Friedrich
7:22 16 Jul '04  
Nemanja,

I'm glad that someone has set out to explain the details of the export keyword and its implications at last. I do agree with you that it should be implemented by MSVC++ for standard conformance and thus source code portability.
On the other hand, however, I do agree with Herb Sutter in that the effort of this is not worth the benefits. It is the lack of export for some aspects of templates that prevent "export" from being the real mccoy. Therefore, even in presence of a working "export", I'd stick to explicit/manual template instantiation - simply for reasons of uniformity in coding.
Another (IMHO) promising alternative are template repositories as the implemented by e.g. DEC's CXX 6.x compilers. With regard to "export", it is sad that this approach has been dismissed by the ISO/ANSI committee.

Bye,

Martin Friedrich

GeneralRe: Finally, a clarification on "export"
Nemanja Trifunovic
7:57 16 Jul '04  
Thanks for your input Martin.

Martin Friedrich wrote: On the other hand, however, I do agree with Herb Sutter in that the effort of this is not worth the benefits.
Herb is probably right. However, the EDG team has already successfully implemented this feature, so I guess it would require less effort to implement it on other compilers. The funny thing is that even EDG based compilers (with exception of Comeau) don't expose export to the users.

Anyway, export is not a must-have feature. I just speculated that it might improve the readability of template libraries.


My programming blahblahblah blog. If you ever find anything useful here, please let me know to remove it.


Last Updated 12 Jul 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010