Click here to Skip to main content
Click here to Skip to main content

Standard Features Missing From VC++ 7.1. Part II: export

, 11 Jul 2004
Rate this:
Please Sign up or sign in to vote.
Another standard feature missing from MSVC++ 7.1

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Nemanja Trifunovic
Software Developer (Senior) SAP
United States United States
Born in Kragujevac, Serbia. Now lives in Boston area with his wife and daughters.
 
Wrote his first program at the age of 13 on a Sinclair Spectrum, became a professional software developer after he graduated.
 
Very passionate about programming and software development in general.

Comments and Discussions

 
QuestionWhere is the problem? Pinmembernutty1-Oct-04 0:06 
AnswerRe: Where is the problem? PinmemberNemanja Trifunovic1-Oct-04 3:26 
GeneralAn alternative approach PinmemberNiklas Lindquist20-Sep-04 23:15 
GeneralFinally, a clarification on &quot;export&quot; PinmemberMartin Friedrich16-Jul-04 7:22 
GeneralRe: Finally, a clarification on &quot;export&quot; PinmemberNemanja Trifunovic16-Jul-04 7:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 12 Jul 2004
Article Copyright 2004 by Nemanja Trifunovic
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid