4

I know constructor do not have a return type. Though I wonder, what is the type of a constructor then? Does a constructor have a type?

I tried this

struct A { A() {} };

template <typename A> struct foo;

int main() { foo< decltype(&A::A) > f; }

to get the error (gcc)

prog.cc: In function 'int main()':
prog.cc:5:32: error: taking address of constructor 'constexpr A::A(A&&)'
    5 | int main() { foo< decltype(&A::A) > f; }
      |                                ^
prog.cc:5:35: error: template argument 1 is invalid
    5 | int main() { foo< decltype(&A::A) > f; }
      |                                   ^

...well, ok I cannot take the address. Also this fails:

int main() { foo< decltype(A::A) > f; }

with

prog.cc: In function 'int main()':
prog.cc:5:32: error: decltype cannot resolve address of overloaded function
    5 | int main() { foo< decltype(A::A) > f; }
      |                                ^
[...]

which is probably just a very confusing error message caused by the same reason as above (cannot take adress of constructor) and I dont know what else to try..

What is the type of a constructor?

If it has no type, then what is it? Certainly it is not A (member_function)().

PS: To clarify what is my confusion: cpprefernce states

Constructor is a special non-static member function of a class that is used to initialize objects of its class type.

And my logic goes like this: Member function have a type, constructors are special kinds of member functions, hence they should have a type. I know the reasoning is flawed, but why?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • If it doesn't have a return type it doesn't have a type. – user207421 Jul 26 '19 at 10:15
  • @user207421 not very convincing. An `int` does not have a return type and its type is `int` – 463035818_is_not_an_ai Jul 26 '19 at 10:16
  • 1
    @formerlyknownas_463035818 Because it isn't a function... – Lightness Races in Orbit Jul 26 '19 at 10:19
  • @formerlyknownas_463035818 Not very convincing. The question is about constructors, not built-in types. – user207421 Jul 26 '19 at 10:19
  • @FedericoklezCulloca I guess so, but for example cppref states "Constructor is a special non-static member function of a class that " and usually member functions do have a type – 463035818_is_not_an_ai Jul 26 '19 at 10:20
  • 2
    "An `int` does not have a return type and its type is `int`" what a legend – SuperSimplePimpleDimple Jul 26 '19 at 10:21
  • 1
    And usually 'special' indicates some exception to the general rule, and this is one of them. Another is that you can't call it directly, and another is that you can't take its address, and yet another is that it doesn't have a name for name lookup purposes. – user207421 Jul 26 '19 at 10:21
  • @SuperSimplePimpleDimple no it is not `void`. And the "bufoon" was refering to a plain `int` in a snarky comment of mine. – 463035818_is_not_an_ai Jul 26 '19 at 10:24
  • 2
    @SuperSimplePimpleDimple please stay classy. Calling someone a "bufoon" helps no-one and will probably get your otherwise useful comment flagged. – Federico klez Culloca Jul 26 '19 at 10:26
  • @LightnessRacesinOrbit ok I didn't read it all, I commented too fast because it was a funny statement that "ints don't have return types and they still have types" and the guy who said "because they are not functions" - I thought he was saying that constructors are not functions. – SuperSimplePimpleDimple Jul 26 '19 at 10:31
  • 1
    @SuperSimplePimpleDimple just because something is implemented "low level" the same way a function is, doesn't say anything about its type. C++ types are a purely theoretical concept and shouldn't be confused with the way common C++ implementations deal with them. – PeterT Jul 26 '19 at 10:33
  • @PeterT I agree with the second part of that statement, However I think I found the solution to this "problem". I will try to do something, if I don't get an error I will send the code in an answer. – SuperSimplePimpleDimple Jul 26 '19 at 10:38
  • @SuperSimplePimpleDimple just remember that in languages with undefined behavior (like C++) "If I don't get an error" is not a bar high enough to consider something correct. – Federico klez Culloca Jul 26 '19 at 10:40
  • 1
    @SuperSimplePimpleDimple PeterT is right and maybe thats your misunderstanding. The question was not aiming at understaning how the compiler implements constructors. Actually even if I knew what type a constructor is I cannot do much with that information, in that sense its a rather academical question. – 463035818_is_not_an_ai Jul 26 '19 at 11:24
  • @SuperSimplePimpleDimple It was me, and I wasn't. – Lightness Races in Orbit Jul 26 '19 at 12:09
  • The point of a function type is to a pointer to it. The point of a pointer is to have multiple things it can point to. – curiousguy Aug 19 '19 at 09:53
  • @curiousguy kind of makes sense, though it doesn't seem that thats the rule the comitee follows when introducing a type. `nullptr_t` is what comes to my mind as perfect counter example – 463035818_is_not_an_ai Aug 19 '19 at 10:04
  • @formerlyknownas_463035818 C++ had many such UDT (user defined type, not user is in the end user, but not builtin types): the original STL is filled with tag types (a zero information type used to distinguish overloads); only true support for both lambda and concepts can make these bunch of tags redundant. Going back to ctors, since they don't have names, the only way to have two that took the same runtime parameter was a tag (think "complex(x,y)" vs "complex(theta,arg)") like "complex(theta,arg,polar())". In the language support lib, there is also the non throwing `new` operator. – curiousguy Aug 19 '19 at 18:26

3 Answers3

9

I think these quotes from the C++ 17 Standard will be relevant (15.1 Constructors)

1 Constructors do not have names....

and

2 A constructor is used to initialize objects of its class type. Because constructors do not have names, they are never found during name lookup; however an explicit type conversion using the functional notation (8.5.1.3) will cause a constructor to be called to initialize an object. [ Note: For initialization of objects of class type see 15.6. — end note ]

and

10 A return statement in the body of a constructor shall not specify a return value. The address of a constructor shall not be taken.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Could you also add: `A return statement in the body of a constructor shall not specify a return value. The address of a constructor shall not be taken.` --> 11.3.4 6 – KostasRim Jul 26 '19 at 10:21
5

Constructors effectively do not have types.

It may be surprising that the standard doesn't say this explicitly, but since they do not have names, do not participate in name lookup, cannot have their address taken and are "functions" with no return type, it's deducible.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 2
    `Constructors effectively do not have types.` I would expect that majority of compilers interpret it as `void` return type. Functionally it is the same. – Piotr Siupa Jul 26 '19 at 10:23
  • @NO_NAME good point. It may be worth to inspect how `void` functions are translated to assembly and whether constructors are similar in this case. – Fureeish Jul 26 '19 at 10:25
  • @NO_NAME It is possible that, in the generated code, a constructor looks a bit like a `void`-returning member function, yes. But that tells us nothing about the actual type in actual C++ – Lightness Races in Orbit Jul 26 '19 at 10:26
  • @NO_NAME No. I would not only expect but *demand* that all compilers interpret it as expressed in the standard. If you can find an exception please provide it here. – user207421 Jul 26 '19 at 10:27
  • @user207421 If you have a quote from the standard which says that constructors need to return void, please write an answer to the question. – Piotr Siupa Jul 26 '19 at 10:41
  • @NO_NAME They don't, and it doesn't, and that is exactly the point. – Lightness Races in Orbit Jul 26 '19 at 12:09
0

If they had a type, what could you do? Exactly nothing. This is why:

If they had one, you might be able to get the pointer to a constructor by taking its address (taking the address of an overloaded entity is unambiguous if the result is used syntactically immediately to initialize a pointer of the right type).

If they had pointers to them, what could you do? Exactly nothing.

They don't have a name. A non null pointer to constructor of A will always point to &A::A. You might as well remove the pointer boilerplate and "call the constructor" directly.

curiousguy
  • 8,038
  • 2
  • 40
  • 58