3

Take this class:

class Foo {
public:
   using MyType = Foo;

   MyType* m = nullptr; //ok

   MyType* functor() { //ok
      return nullptr;
   }

   MyType() = default; //error
   ~MyType() = default; //error
};

Why can you use alias names for members, but not for constructors or destructors?

TwistedBlizzard
  • 931
  • 2
  • 9
  • Refer to [how to ask](https://stackoverflow.com/help/how-to-ask) where the first step is to *"search and then research"* and you'll find plenty of related SO posts for this. – Jason Nov 26 '22 at 03:30
  • See [Can typedef names be used to declare or define constructors?](https://stackoverflow.com/questions/11478962/can-typedef-names-be-used-to-declare-or-define-constructors). – Jason Nov 26 '22 at 03:31

2 Answers2

5

Since this is tagged language-lawyer, lets see what the standard has to say.

From [class.ctor.gen], emphasis added:

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:

(1.1) in a friend declaration ([class.friend]), the id-expression is a qualified-id that names a constructor ([class.qual]);
(1.2) 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;
(1.3) otherwise, the id-expression is a qualified-id whose unqualified-id is the injected-class-name of its lookup context.

For the subject of why a name alias is not valid to declare constructor, especially (1.2) is of relevance. It states that the id-expression is the injected-class-name [..]. The latter is defined in [class.pre]:

  1. A class is a type. Its name becomes a class-name ([class.name]) within its scope.
    [..]
  2. The class-name is also bound in the scope of the class (template) itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name. [..]

This states very plainly, that the injected-class-name is exactly the name used to declare the class in the first place. There is no allowance in the wording for aliases.


This follows the same mechanism that you see in a class template:

template <typename T> class C { C foo(); };

Now, there is no class named C, C is a template, so you would normally expect to have to say C<T> foo();. But as stated in [class.pre], a class-name is introduced in the scope of the class definition which refers to the actual type. So, even if there is no class C anywhere, the class-name C can be used as a shorthand for C<T> and in the case of constructors and destructors, is the only way to refer to it because their declaration does not allow you to use any type-id, but only class-name.

bitmask
  • 32,434
  • 14
  • 99
  • 159
3

m is a pointer to an instance of a type, which is aliased. OK.

functor() returns a pointer to an instance of a type, which is aliased. OK.

But a constructor/destructor is not itself a type, so you can't use a type alias for them. They must be named after the type they belong to. That is just the way the syntax works

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770