Common syntax errors in C++

These are some common syntax errors that were accepted by some older compilers but are reported and rejected by newer versions, particularly g++ version 4.

My templates FAQ covers some other issues related to syntax and name lookup in templates that can appear when upgrading or switching compiler.

Reliance on friend name injection

The Annotated Reference Manual (ARM), an early description of C++, stated that a declaration friend functions in a class was treated as a declaration in the surrounding namespace (this is called "friend name injection").

This is an exception to the general rule that names must be defined or overloaded in a block associated with the scope they are defined in. It has particularly odd effects for class templates, as a friend declaration in a class template will only be instantiated along with the rest of the template.

In standard C++, friend name injection is not performed. Friend functions that need to be found by ordinary name lookup (as opposed to argument-dependent lookup) must first be declared in the class's namespace.

class foo;

class bar
{
    // ...
    foo * foo _;
};

class foo
{
    // ...
    friend int baz(const bar &);
};

int main()
{
    return baz(bar());
}
class foo;

class bar
{
    // ...
    foo * foo _;
};

class foo
{
    // ...
    friend int baz(const bar &);
};

int baz(const bar &);

int main()
{
    return baz(bar());
}

Extra qualification of members

Old versions of g++ and current versions of Visual C++ allow member declarations to use names that are qualified by the name of the class.

However, this is a syntax error in standard C++. All member declarations must use an unqualified name for the member itself.

class foo
{
public:
     foo::foo();
};
class foo
{
public:
     foo();
};

Specialisation in a different namespace

Old versions of g++ would allow you to specialise or explicitly instantiate a template in a namespace other than the one it was declared in, so long as the template's name is visible.

In standard C++ this is a syntax error. All declarations for a particular template must be made in the same namespace.

template<typename T> class foo;

namespace bar
{
    // ...

    template<> class foo<int>;
}
template<typename T> class foo;

namespace bar
{
    // ...
}

template<> class foo<int>;

Undefined escape sequences in literal strings

The backslash character can be used in literal strings and characters:

  1. to escape various characters that have special significance in a literal string or character (", ', \ and ?), and
  2. to introduce an escape sequence representing a character that it is impossible or impractical to include in the program literally (new-line, delete, etc.)

Where a backslash is followed by a character that doesn't begin a sequence of the second type, some compilers always treat this as a sequence of the first type. This allows characters to be "escaped" even where this is not necessary. This can hide bugs where the backslash itself should be escaped, for example in regular expressions.

In standard C++ (and C) only specific escape sequences are defined; the behaviour of others is undefined. Recent versions of g++ treat undefined escape sequences as errors.

std::tr1::regex dot_name("^\.*([a-z]+)\n")
std::tr1::regex dot_name("^\\.*([a-z]+)\n")

Ben Hutchings
Last modified: Fri Mar 31 00:17:50 BST 2006