16

In C++, is it possible to start a class name with a digit? For example,

template <class T> class 2DArray {

public:
    // 1D ARRAY CLASS
    class 1DArray {
    public:
        1DArray() { Create(); }
        1DArray(iterator arr) : array1d_(arr) { }
        explicit 1DArray(size_type cols, const T& t = T()) { Create(cols, t); }
        1DArray(const 1DArray& arr) { Create(arr.begin(), arr.end()); }
        1DArray& operator=(const 2DArray&);
        ~1DArray() { Uncreate(); }

        T& operator[](size_type n) {
            return array1d_[n];
        }
        const T& operator[](size_type n) const {
            return array1d_[n];
        }
}
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Erika Electra
  • 1,854
  • 3
  • 20
  • 31

4 Answers4

28

Rules for identifier names in C++ are:

  1. It can not start with a number
  2. Can be composed of letters, numbers, underscore, universal character names1 and implementation defined characters
  3. Can not be a keyword.

The sections in the C++ draft standard that cover this are 2.11 Identifiers which includes the following grammar:

identifier:
  identifier-nondigit            <- Can only start with a non-digit
  identifier identifier-nondigit <- Next two rules allows for subsequent 
  identifier digit               <-  characters to be those outlined in 2 above
identifier-nondigit:
  nondigit                       <- a-z, A-Z and _ 
  universal-character-name
  other implementation-defined characters
[...]

and 2.12 Keywords explains all the identifier reserved for use as keywords.

Finally, the following names are also reserved:

  1. Names that contain a double underscore __, or start with either an underscore followed by an uppercase letter (like _Apple) in any scope,
  2. Names that start with an underscore in the global namespace (like _apple in the global namespace) are reserved.

The section that covers this in the draft standard is 17.6.4.3.2. We can find a rationale for why these are reserved from Rationale for International Standard—Programming Languages—C which says:

[...]This gives a name space for writing the numerous behind-the-scenes non-external macros and functions a library needs to do its job properly[...]

In C++ this also applies to name mangling as this example shows.


Footnotes

  • 1. Allowed universal characters

The universal characters that are allowed is covered in Annex E.1:

E.1 Ranges of characters allowed [charname.allowed]

00A8, 00AA, 00AD,

00AF, 00B2-00B5, 00B7-00BA, 00BC-00BE, 00C0-00D6, 00D8-00F6, 00F8-00FF

0100-167F, 1681-180D, 180F-1FFF 200B-200D, 202A-202E, 203F-2040, 2054,

2060-206F 2070-218F, 2460-24FF, 2776-2793, 2C00-2DFF, 2E80-2FFF

3004-3007, 3021-302F, 3031-303F

3040-D7FF F900-FD3D, FD40-FDCF,

FDF0-FE44, FE47-FFFD

10000-1FFFD, 20000-2FFFD, 30000-3FFFD, 40000-4FFFD, 50000-5FFFD, 60000-6FFFD, 70000-7FFFD, 80000-8FFFD, 90000-9FFFD, A0000-AFFFD, B0000-BFFFD, C0000-CFFFD, D0000-DFFFD, E0000-EFFFD

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • This is really true of any C-like language too, or at the very least almost all. – Austin T French Mar 08 '13 at 02:47
  • 2
    Clarification: Contain a double underscore or start with an underscore followed by a capital letter, or start with an underscore in the global scope. – chris Mar 08 '13 at 02:50
  • @AthomSfere, in C, names that contain `__` are not reserved, only those _starting_ with it. – Shahbaz Mar 19 '13 at 15:37
4

The simple answer is no. For you example why not call it OneDArray?

jv110
  • 353
  • 2
  • 13
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • 3
    That's ugly, and you're solving the wrong problem. Instead of substituting the digit with something else, why not change the name to, say, `Array1D`? – jv110 Dec 13 '17 at 07:17
4

Since, surprisingly, I wasn't able to find a duplicate, or more general version, of this question, here is an answer based on what the Standard (C++11) says.

First of all, by §9/1, a class name is an identifier (or a simple-template-id in the case of a template specialization, but a simple-template-id is also composed of identifiers).

§2.11 defines what a valid identifier is. It first introduces a few basic concepts:

A digit is one of these: 0 1 2 3 4 5 6 7 8 9
A nondigit is one of these: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
A universal-character-name is a sequence of type \unnnn or \Unnnnnnnn (where each n is a hexadecimal digit)

The Standard then defines an identifier-nondigit as

  • either a nondigit
  • or a universal-character-name
  • or an implementation-defined special character(&ddagger;)

Finally, identifier is defined recursively as

identifier:
  identifier-nondigit
  identifier identifier-nondigit
  identifier digit

Summary: In other words, an identifier must start with a (non-digit!) alphabetical character, which can be followed by anything made up of alphanumerical characters, underscores and \unnnn-like character references. Anything else is implementation-specific.


(&ddagger;) Whether any are supported depends on your compiler, and using them generally means you lose portability to other compilers or compiler versions.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
  • 2
    Thank you for the clear summary, though I am not sure why it was surprising. If I found the answer on Google or Stack Overflow, I wouldn't have asked. The recursive standard-speak, too, eludes my simple brain; my understanding got as far as the class name being an identifier, and then the identifier identifier-nondigit part just makes no sense to me. – Erika Electra Mar 08 '13 at 04:55
  • @Cindeselia Yes, of course. I wasn't surprised by your asking the question. I am surprised about the fact nobody asked it before. – jogojapan Mar 08 '13 at 04:56
  • @Cindeselia Oh, regarding the _identifier_ definition: You need to read every line as an alternative. So an _identifier_ is either a _identifier-nondigit_, or _identifier_ followed by _identifier-nondigit_ or _identifier_ followed by _digit_. So, _identifier_ occurs in its own definition and can be recursively replaced with further instances of that definition. Any sequence you can possibly form from this will always start with an _identifier-non-digit_. – jogojapan Mar 08 '13 at 05:01
1

Names in C++ must start with a 'letter', where letter is all the upper and lower case 'A-Z, a-z'. '_' also counts as a 'letter'. It can then be followed by any combination of letters and digits.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • 1
    So _2DArray should be okay? – Erika Electra Mar 08 '13 at 04:56
  • 1
    @Cindeselia depends, any names in the global namespace that starts with an `_` is reserved and should not used. This previous thread clarifies global Vs. non-global namespaces in case you are not sure http://stackoverflow.com/questions/10269012/global-scope-vs-global-namespace – Shafik Yaghmour Mar 08 '13 at 05:05
  • 1
    @Cindeselia This previous thread suggests not using leading underscores in names just to sure http://stackoverflow.com/questions/224397/why-do-people-use-double-underscore-so-much-in-c – Shafik Yaghmour Mar 08 '13 at 05:11