C H A P T E R  2

Using Compatibility Mode

This chapter describes how to compile code that was intended for the C++ 4 compilers.


2.1 Compatibility Mode

The compiler options for compatibility mode are (both versions mean the same thing):


-compat
-compat=4

For example:


example% CC -compat -O myfile.cc mylib.a -o myprog

There are some minor differences between using the C++ 4 compilers and the C++ 5 compilers in compatibility mode, as described in the following sections.


2.2 Keywords in Compatibility Mode

By default, some of the new C++ keywords are recognized as keywords in compatibility mode, but you can turn off most of these keywords with compiler options, as shown in the following table. Changing the source code to avoid the keywords is preferable to using the compiler options.


TABLE 2-1 Keywords in Compatibility Mode

Keyword

Compiler Option to Disable

explicit

-features=no%explicit

export

-features=no%export

mutable

-features=no%mutable

typename

cannot disable


Keyword typename cannot be disabled. The additional new C++ keywords, described in TABLE 3-1, are disabled by default in compatibility mode.


2.3 Language Semantics

The C++ 5 compilers do a better job of enforcing some C++ language rules. They are also less permissive about anachronisms.

If you compile with C++ 4 and enable anachronism warnings, you might discover code that has always been invalid, but that much older C++ compilers accepted anyway. It was always explicit policy (that is, stated in the manuals) that the anachronisms would cease to be supported in future compiler releases. The anachronisms consist mainly of violating access (private, protected) rules, violating type-matching rules, and using compiler-generated temporary variables as the target of reference parameters.

The remainder of this section discusses the rules that previously were not enforced, but are now enforced by the C++ compiler.



Note - These rules are enforced by the C++ compiler in both compatibility mode and standard mode.



2.3.1 Copy Constructor

When initializing an object, or passing or returning a value of class type, the copy constructor must be accessible.


class T {
  T(const T&); // private
public:
  T();
};
T    f1(T t) { return t; } // Error, can't return a T
void f2()    { f1( T() ); } // Error, can't pass a T

Solution: Make the copy constructor accessible. Usually, it is given public access.

2.3.2 Static Storage Class

The static storage class applies to objects and functions, not to types.


static class C {...};   // Error, cannot use static here
static class D {...} d; // OK, d is static

Solution: In this example, the static keyword does not have any meaning for class C and should be removed.

2.3.3 Operators new and delete

When allocating an object with new, the matching operator delete must be accessible.


class T {
    void operator delete(void*); // private
  public:
    void* operator new(size_t);
};
T* t = new T;              // Error, operator delete is not accessible

Solution: Make the delete operator accessible. Usually, it is given public access.

A count is not allowed in a delete expression.


delete [5] p; // Error: should be delete [] p;

2.3.4 new const

If you allocate a const object with new, it must be initialized.


const int* ip1 = new const int;    // Error
const int* ip2 = new const int(3); // OK

2.3.5 Conditional Expression

The C++ standard introduced a change in the rules for conditional expressions. The C++ compiler uses the new rule in both standard mode and compatibility mode. For more information, see Section 1.5, Conditional Expressions.

2.3.6 Default Parameter Value

Default parameter values on overloaded operators or on pointers to functions are not allowed.


T operator+(T t1, T t2 = T(0) );   // Error
void (*fptr)(int = 3);             // Error

Solution: You must write the code some other way, probably by providing additional function or function pointer declarations.

2.3.7 Trailing Commas

Trailing commas in function argument lists are not allowed.


f(int i, int j, ){ ... } // Error

Solution: Remove the extra comma.

2.3.8 Passing of const and Literal Values

Passing a const or literal value to a nonconstant reference parameter is not allowed.


void f(T&); 
extern const T t; 
void g() {
    f(t); // Error
}

Solution: If the function does not modify its parameter, change the declaration to take a const reference (for this example, const T&). If the function modifies the parameter, you cannot pass it a const or a literal value. An alternative is to create an explicit nonconstant temporary and pass that instead. See Section 3.7, String Literals and char* for related information.

2.3.9 Conversion Between Pointer-to-Function and void*

The C++ compiler, in both compatibility and standard mode, now issues a warning for implicit and explicit conversions between pointer-to-function and void*. For more information, see Section 1.6, Function Pointers and void*.

2.3.10 Type enum

If an object of enum type is assigned a value, that value must have the same enum type.


enum E { zero=0, one=1 };
E foo(E e)
{
   e = 0;    // Error
   e = E(0); // OK
   return e;
}

Solution: Use a cast.

2.3.11 Member-Initializer List

The old C++ syntax of implied base-class name in a member-initializer list is not allowed.


struct B { B(int); };
struct D : B {
    D(int i) : (i) { }    // Error, should be B(i)
};

2.3.12 const and volatile Qualifiers

const and volatile qualifiers on pointers must match properly when passing arguments to functions, and when initializing variables.


void f(char *); 
const char* p = "hello";
f(p);              // Error: passing const char* to non-const char*

Solution: If the function does not modify the characters it points to, declare the parameter to be const char*. Otherwise, make a nonconstant copy of the string and pass that instead.

2.3.13 Nested Type

Nested types cannot be accessed from outside the enclosing class without a class qualifier.


struct Outer {
    struct Inner { int i; };
    int j;
};
Inner x;            // Error; should be Outer::Inner

2.3.14 Class Template Definitions and Declarations

In class template definitions and declarations, appending the type argument bracketed by < > to the class's name has never been valid, but versions 4 and 5.0 of the C++ compiler did not report the error. For example, in the following code the <T> appended to MyClass is invalid for both the definition and the declaration.


template<class T> class MyClass<T> { ... }; // definition
template<class T> class MyClass<T>;         // declaration

Solution: Remove the bracketed type argument from the class name, as shown in the following code.


template<class T> class MyClass { ... }; // definition
template<class T> class MyClass;         // declaration


2.4 Template Compilation Model

The template compilation model for compatibility mode is different from the 4.2 compilation model. For more information about the new model, refer to Section 3.3.5, Template Repository.