c++functionconstructorlanguage-lawyermember-functions

Is a constructor, that is not a special member function, still a member function?


From the C++ standard working draft:

Default constructors ([class.default.ctor]), copy constructors, move constructors ([class.copy.ctor]), copy assignment operators, move assignment operators ([class.copy.assign]), and prospective destructors ([class.dtor]) are special member functions.

(https://eel.is/c++draft/special)

Given the following code:

struct S {
    S(int, float, double);
};

In my understanding, the constructor of S is not a special member function, since it is neither a default constructor, copy constructor, nor move constructor.

I would like to know whether the standard still considers such as constructor a member function (or something "unique").

I read the parts of the C++ working draft about member functions, special member functions, and constructors, but didn't find anything reasonable answering this question. I also looked on StackOverflow, but most answers state that all constructors are considered special member functions, which seems to contradict the standard.


Solution

  • tldr;

    A constructor is declared using a function-declarator and so it is a function and hence a member function.


    Language-lawyered Explanation

    class.mem states:

    The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere. A direct member of a class X is a member of X that was first declared within the member-specification of X, including anonymous union members ([class.union.anon]) and direct members thereof. Members of a class are data members, member functions ([class.mfct]), nested types, enumerators, and member templates ([temp.mem]) and specializations thereof.

    Now we move onto class.mem#general-3 to see what is a member function:

    A data member is a non-function member introduced by a member-declarator. A member function is a member that is a function. Nested types are classes ([class.name], [class.nest]) and enumerations ([dcl.enum]) declared in the class and arbitrary types declared as members by use of a typedef declaration ([dcl.typedef]) or alias-declaration. The enumerators of an unscoped enumeration defined in the class are members of the class.

    Now we need to show that a ctor is a function so we move onto class.ctor.general#1:

    A declarator declares a constructor if it is a function declarator ([dcl.fct]) of the form

    ptr-declarator ( parameter-declaration-clause ) noexcept-specifieropt attribute-specifier-seqopt
    

    where the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:

    • in a friend declaration ([class.friend]), the id-expression is a qualified-id that names a constructor ([class.qual]);
    • otherwise, in a member-declaration that belongs to the member-specification of a class or class template, the id-expression is the injected-class-name ([class.pre]) of the immediately-enclosing entity;

    The important thing to note is that a ctor is declared using a declarator which is a function declarator. Now to see that the ctor's function declarator declares a function we move onto dcl.spec.auto.general:

    A placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type ([dcl.fct]), that trailing-return-type specifies the declared return type of the function. Otherwise, the function declarator shall declare a function. If the declared return type of the function contains a placeholder type, the return type of the function is deduced from non-discarded return statements, if any, in the body of the function ([stmt.if]).

    Now since the ctor's function declarator form doesn't include a trailing return type, the ctor's function declarator declares a function as per the above reference.

    Hence proved, the ctor S::S(int, float, double) is a function and so a member function.

    Additional support

    There is additional support for the statement that a constructor is a function in dcl.constexpr:

    A function is constexpr-suitable if:

    • if the function is a constructor or destructor, its class does not have any virtual base classes.

    This also indicates that a constructor is a function.


    Layman Explanation

    Is a constructor, that is not a special member function, still a member function?

    Yes, because the constructor S::S(int, float, double) is declared inside the member-specification of the class S so the declaration is by definition a member function declaration.

    Basically, declarations inside the member-specification of the class are member declarations. If the declaration is of a


    So yes, S::S(int, float, double) is a member function.