RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


C++0x Forward Enum Declarations Cut Down Compilation Time and Dependencies : Page 2

A new C++0x feature called forward enum declarations allows you to declare an enumeration without providing its enumerators list. Learn how using it can avert long compilation times and ODR violations.


The Repeated Enumerators List Problem

In many C++ projects, enum types that contain hundreds of enumerators are quite common. Often, these enum types are machine-generated and updated frequently. Examples of such huge enum types include a list of international airports, a list of locales supported by the application, and so on.

The problem is that whenever you update such an enum, every translation unit that references it must be compiled as well—even if the code that references the enum hasn't changed. Consider the list of airports as an example:

//file: airports.h
#ifndef AIRPORTS_H 
#define AIRPORTS_H 

enum class Airports: int
//..many more entries
//..many more entries

Seemingly, the following piece of code doesn't depend on the list of Airports' enumerators, as adding a new enumerator, changing an existing enumerator, or deleting one doesn't affect Airports' enum base (which is int):

#include "airports.h"
std::istream& operator>>(std::istream& is, Airports& ap);
std::string get_ap_name(Airports ap);

Airports ap;
std::cin >> ap;
std::cout << get_ap_name(ap);

Theoretically, the compiler can process this code without needing a complete definition of Airports, but that isn't the case. C++03 requires the presence of the entire list of enumerators to determine the underlying type of Airports. This leads to a longer compilation time and increases the risk of ODR(One Definition Rule) violations.

Scoped Enums and Enum Bases

Before diving deeper into forward declaration of enum types, you need to understand two key concepts: scoped enum types and enum bases. A scoped enum is one that is declared with the class keyword, as opposed to a traditional enum, which is unscoped.

Among other things, scoped and unscoped enums differ with respect to enumerator qualification:

enum class A {x,y}; //scoped
enum B {t,u}; //unscoped
A a1=A::x; //OK, qualified enumerator
A a2=y; //error, y is unqualified
B b=t; //OK, unscoped. Enumerator isn't qualified

As previously stated, an enum base is the underlying integral type of the enumeration. Recall that the compiler represents every enum type as an unspecified integral type that is large enough to hold every enumerator value. For scoped enums, the default base type is int. You can override it by specifying a different enum base explicitly, like this:

enum class A {x,y}; //scoped, base is int
enum class Q: char {x,y}; //scoped, base is char

In C++0x, an unscoped enum may also include an explicit enum base. Notice, however, that unlike scoped enums, an unscoped enum doesn't have a default enum base:

enum C: int {x,y}; //unscoped, enum base is int
enum D {x,y}; //unscoped, no enum base

This presents a problem: the compiler must know what the enum base is to compile any piece of code that refers to that enum. Now you are ready to learn how forward declarations solve this problem.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date