I am referring to this excellent blog post regarding the "Unforgettable Factory Registration Pattern": http://www.nirfriedman.com/2018/04/29/unforgettable-factory/
I've noticed that this stops working when the self-registering types are default constructible. In the example provided by the code, the self-registering types (Animal base class) defines a constructor with an int parameter. If I slightly modify the code to make Animal become default constructible, the data map in the factory remains empty and objects of type Cat and Dog can no longer be constructed through the factory.
As far as I understand the issue lies in the fact that the Animal class no longer calls the registerT function. However, I fail to understand why that is and what modification(s) are necessary to make it work with default constructible classes.
Can somebody shed some light on this?
Useful:
Modified example: http://coliru.stacked-crooked.com/a/55fe8edc094c88a8
Original example: http://coliru.stacked-crooked.com/a/11473a649e402831
The int argument is a red herring. When changing the argument list you modified
Dog(int x) : m_x(x) {}
to be
Dog() = default;
From a user-provided constructor, to a defaulted one.
In effect, this means the compiler (I checked Clang and GCC) doesn't emit a function definition for Dog::Dog(), so it doesn't odr-use Animal::Registrar<Dog>::Registrar<Dog>(), which means its definition isn't instantiated (member function bodies only are only instantiated when odr-used). And so we never odr-use its registered static data member.
If the constructor is defaulted, then we never actually end up registering the factory function into the map. And indeed, after it becomes user-provided again, things start to work.
I am however unable to understand why that makes a difference. The user-provided constructor is still an inline member function. And inline function definitions are tied to odr-usage too. But perhaps that should be the subject of another question.
Related
I recently learnt that constructors do not have names in C++ and some other things about them. I am also aware that a function has a type in C++ called a function type. For example,
void func(int)
{
}
In the above snippet the func has the function type void (int).
Now, I want to know that since constructors are special member functions then do they also have a type like the one shown above. For example say we have:
struct Name
{
Name(int)
{
}
};
Does the constructor shown above also has a function type just like ordinary functions or ordinary member functions. If yes, then how can we find that type. Like we can use decltype on ordinary functions, is it permitted to use decltype on constructors to find their type.
is it permitted to use decltype on constructors to find their type
It's not permitted. Primarily because there is no way to name a constructor. A common misnomer is that an expression like Name(0) or new Name(0), calls the constructor. But that isn't the case like in func(0). A constructor is never called by us directly, but rather always indirectly by the language construct that requires a new object to come into being.
[class.ctor.general]
1 ... Constructors do not have names.
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 ([expr.type.conv]) will cause a constructor to be called to initialize an object.
[Note 1: The syntax looks like an explicit call of the constructor. — end note]
Because we cannot name them, we cannot use introspection mechanisms like decltype to examine them. Therefore the standard doesn't specify a "type" for constructors, since there is no way for a strictly standard compliant program to examine said type.
A constructor also cannot possess a signature (as defined by the standard), since that by definition includes the function name (and constructors are, as mentioned, nameless).
[defns.signature.member] signature
⟨class member function⟩ name, parameter-type-list, class of which the function is a member, cv-qualifiers (if any), ref-qualifier (if any), and trailing requires-clause (if any)
A classes constructor is never called explicitly. You instantiate an object using something like new Name(5), memory will be allocated and then some part of that memory may be initialized by the steps defined in the constructors body.
Notice that a constructor has no return statement. What is returned by new Name(5) is a memory reference to the memory allocated by new.
This is given away by syntax like:
Name * foo = new Name(5)
foo is the pointer to whatever has be allocated and type checking can be done because Name referrs to a class, not to its constructor.
I am learning about classes in C++ and know that non-static member functions have implicit this parameter. My first question is that does constructor also have an implicit this parameter just like non-static member functions. Note that i am not asking whether we can use this inside a ctor as i already know that we can use this inside a ctor.
Next, I know that inside a const qualified non-static member function for a class X, the type of this is const X*. And for a non-static member function(without const qualified), the type of this is X*. Similarly, inside the ctor the type of this is always X*. Here comes the deeper question.
We know that when we call a non-static member function(say like obj.func()), then the address of the object named obj is implicitly passed to the implicit this parameter of the method func. So this explains "where the this comes from in case of non-static member function".
Now, lets apply the same thing to constructors. For example, say we create an object of class X using default ctor like:
X x; //does the default ctor also have an implicit this parameter to which the address of x is passed?
My second question is: Does the same thing happen to ctors? Like, the address of x is passed to an implicit parameter of the default ctor. My current understanding is that ctors don't have an implicit this parameter. So when we write X x;, the address of x is not passed as an argument because the object is not created yet and so it doesn't make sense to pass its address. But from the standard we know that inside a ctor we can use the this pointer. So my second question essentially is that, if ctors don't have an implicit this parameter then where does the this in the statement this->p = 0; come from? We know that before using any name(like variable name) in C++, we must have a declaration for that name. So where is the declaration for this? Does the compiler implicitly declares the this in case of ctor? I mean, in case of non-static member function, i can understand that they have the declaration for this as the implicit this parameter but what happens in ctors? How inside ctors we're able to use the name this without having a declaration for that?
struct Name
{
private:
int p = 0;
int k = 0;
void func() //func is a non-static member function and so have an implicit this parameter
{
this->k = 0; // the "this" here comes from implicit this parameter
}
Name()
{
this->p = 0; //where does the "this" comes from here since ctor don't have implicit this parameter
}
};
My third question is that is the concept of implicit this parameter an implementation detail or does the standard says that non-static member function will have an implicit this parameter.
Summary
Do ctors have an implicit this parameter? This first question can also be phrased as "Do ctors also have an implicit object parameter?".
The standard says that we can use this inside a ctor. But where does that this come from. For example, in case of a non-static member function, we know that this comes from the implicit this parameter, but in case of ctors, since ctors don't have an implicit this parameter, where does that this that we're allowed to use inside ctor come from.
Is the concept of implicit this parameter an implementation detail or does the standard say that all non-static member functions have an implicit this parameter, in which case, ctors are also allowed by implementations to have an implicit this parameter.
Edit:
The most important part(IMO) of this question is that how are we able to use the name this inside a ctor? For example when we write:
this->p = 0; //here "this" behaves like a name
In the above statement this behaves like a name. And we know that before using any name(like variable name) in C++, we must have a declaration for that name. So where is the declaration for this? Does the compiler implicitly declares the this in case of ctor? I mean, in case of non-static member function, i can understand that they have the declaration for this as the implicit this parameter but what happens in ctors? How inside ctors we're able to use the name this without having a declaration for that?
From the perspective of the C++ standard
The standard only describes the semantics of the this keyword and not how its value gets there. That's completely abstracted away and an implementation has great flexibility in making it happen.
From the perspective of theoretical computer science
The address of the object under construction, available via the this keyword, absolutely is an input to the initialization procedure (called "constructor" in C++) for the object. So are addresses of virtual base subobjects, which C++ also makes available via the this keyword but cannot be calculated from the main input, so any such must be additional inputs.
Note that CS tends to use "parameter" with procedures more in the sense of template parameters than dynamic variable inputs. And CS uses "function" to mean a procedure without side effects. A C++ constructor is not a CS "function" and while templated constructors are possible (parametric procedures) the value of this is an ordinary input not a parameterization.
Neither is a C++ constructor a method -- there is no polymorphic target-type-dependent dispatch, and so in particular the this input is not used for dispatch.
From the perspective of ABI rules for parameter-passing
A C++ constructor is a special member function. There's no way to construct a function pointer for it or invoke it C-style; ABI requirements for C functions do not apply.
If the platform ABI explicitly describes C++ behaviors, then there will be one or more rules for passing the value(s) of this to a C++ constructor. Those rules may or may not specify a mechanism equivalent to other function arguments, but every ABI-compliant C++ compiler targeting that platform will pass this values as required by the special rules for constructors.
Notably, the ABI for passing this to a constructor isn't required to be equivalent to how this is passed to other (non-special and non-static) member functions, although practical ABIs may well use the same approach for both.
There's no such thing as "implicit this parameter" in the standard. The standard calls it an "implicit object parameter".
An implicit object parameter is only relevant to overload resolution, it doesn't "become" this. Separately, this is defined to have the same cv qualification as the member function.
Do ctors have an implicit this parameter? This first question can also be phrased as "Do ctors also have an implicit object parameter?".
No, from [over.match.funcs]
For the purposes of overload resolution, both static and non-static member functions have an implicit object parameter, but constructors do not.
But where does that this come from.
The object being constructed.
Is the concept of implicit this parameter an implementation detail or does the standard say that all non-static member functions have an implicit this parameter, in which case, ctors are also allowed by implementations to have an implicit this parameter.
The implicit object parameter is part of the rules of overload resolution, it doesn't influence this.
How inside ctors we're able to use the name this without having a declaration for that?
this is not a name, it is a language keyword. The language defines this in a non-static member function to be a prvalue expression. Unlike an unqualified-id (that names an object) in the same position, which are glvalue expressions.
That's the language-lawyer answer. Having said that, I do find that "implicit object parameter becomes this" is a useful mental model.
Recall that constructors (and destructors) can't be cv qualified, so there isn't anything for it to distinguish in a constructor, so it doesn't matter if it exists or not.
"this" is a keyword; it doesn't need declaring, but is always available in non-static member functions.
See e.g. the draft standard here.
The keyword this names a pointer to the object for which an implicit object member function is invoked or a non-static data member's initializer is evaluated.
Note that the mechanism behind this is unspecified.
I would like to declare a class with a defaulted constructor1, but I want to this defaulted constructor to be "extern" in the sense the constructor body should only be compiled once, when the TU for the class is compiled, and not in each TU that includes that header. Finally, the class should should not be seen to have a user-provided constructor, but rather a defaulted one2.
For example, here's one attempt:
foo.hpp:
class Foo {
public:
Foo();
};
foo.cpp:
Foo::Foo() = default;
This results in a defaulted constructor implementation, but it means that Foo has a user-provded constructor, which affects the traits of the type, e.g., whether it is trivial, etc.
Here's another way:
foo.hpp:
class Foo {
public:
Foo() = default;
};
This preserves the "not user-provided" property, but now every TU that includes this class and uses the constructor will generate machine code for it (and this code might get inlined, etc).
1 Really, this applies to any special member functions, but I'm using the default constructor here for concreteness.
2 Whether the class has a user-provided constructor affects various important traits and behaviors of the class, such as whether it has a trivial constructor, whether other special member functions are implicitly deleted or not, etc.
There’s no way in the language to tell the compiler that a function is non-user-provided (“you know everything about it”) while also claiming that it’s opaque (“you can’t do the code generation here”). Fortunately, the obvious implementation strategy for C++20 modules has that effect: a member function defaulted in its class in a module interface unit will be considered for inlining everywhere but obviously needs only one out-of-line copy in the object file generated for the module.
If you want a stronger guarantee than that, you’re well into implementation-specific territory and you should look into compiler-specific attributes to govern code generation.
To my surprise, I learned that code like this actually works:
class A {
B b;
C c = this->b.GetC();
}
I guess I've been conditioned into thinking that this is essentially akin to self in Python. However, it also makes sense to me that at the class level we're declaring a template for which every instance of the class is to copy, and at the "declaration" level this shouldn't exist yet. But, C++ never fails to surprise, and the code above seems to work.
That said, is this bad style? What exactly are the differences between the code above, and simply initializing C in the constructor for A?
class A {
B b;
C c;
A() {
c = this->b.GetC();
}
}
(or simply A() : c(this->b.GetC()) {}).
What exactly are the differences between the code above, and simply initializing C in the constructor for A?
This is completely equivalent to A() : c(b.GetC()) {}. There is no difference.
The only difference you will observe is when using multiple constructors. It will use the constructor's initializer instead of the default one if specified.
the "declaration" level this shouldn't exist yet. But, C++ never fails to surprise, and the code above seems to work.
So this can exist at the class level in C++?
No. The initializer is ran when the constructor is called. The member to initialize only exist when an instance is created.
However, it also makes sense to me that at the class level we're declaring a template for which every instance of the class is to copy, and at the "declaration" level this shouldn't exist yet. But, C++ never fails to surprise, and the code above seems to work.
You are kind of right. If you had
struct foo
{
int bar;
decltype(this->bar) baz;
};
then you would get a compiler error for using this at the top level of the class.
In your case though using this like
C c = this->b.GetC();
//or
C c{this->b.GetC()};
isn't actually using this at the top level. A in class member initializer is just syntactic sugar for telling the class that if you do not manually initialize the member then you are to use the initializer provided. So you aren't really using this in the body of the class, you're just using a shortcut.
What exactly are the differences between the code above, and simply initializing C in the constructor for A?
The benefit is if you have some default value you want that memeber to have, you don't have to specify it in all of the constructors you create. You do it once, and your covered. If you ever need to change that value you can't mess it up because there is only one place to change it. You can't forget to do it in a particular constructor which is really nice.
Do note that there is a case where you have to use this in a in class member initializer. If the member you want to use comes from the dependent name, like a template base class, then you need to use this in order for the compiler to resolve the name.
When declaring a class/struct/union the compiler will generate the default methods (rule of three). This also will happen when = default'ing these methods.
How do the default methods exactly look like?
For each of these methods, the compiler defines default inline methods that call the default methods of each attribute of the object. (so a pointer won't be initialized neither any built-in type).
For example let consider the default constructor. According to the C++ Standard
An implicitly-declared default constructor is an inline public member
of its class.
and
The implicitly-defined default constructor performs the set of
initializations of the class that would be performed by a user-written
default constructor for that class with no ctor-initializer (12.6.2)
and an empty compound-statement.
So it looks like
struct A
{
A() {}
};
except that it is not explicitly declared and defined.
About copy constructor you can read at my personal forum
http://cpp.forum24.ru/?1-1-0-00000021-000-0-0-1388485669
Though it is written in Russian but you can translate it for example using google service translate.
Those method will do the minimum necessary to initialize the class.
Default construtor - do nothing with simple members but call the constructors of more complex members (class/struct) as well as call the ctor of its super class.
Copy constructor will perform a shallow copy (memcpy).