In day-01, we have learned how to compile c++ code.
A program written in c++ must be translated to machine code, then the machine code can be executed. The c++ code can not run directly without compiling. The machine code can run directly, but it is not readable by human. The c++ code is readable by human, but it can not run directly.
So there are two stages:
Declaring a variable, the variable type is identified at compile-time:
int x; x = 3;
The type of x is identified as int at compile-time, the allocation of x is at runtime.
The declaration, definition and instantiation of template are done at compile-time.
What is template instantiation? It is explained at day-15 .
I explain it again:
template <typename type_t00> class my_class { };
my_class is a class template; my_class<int>, my_class<char>, ... are classes.
Transforming from my_class to my_class<int> etc. is called template instantiation .
Template is considered as compile-time thing. When it comes to runtime, all templates are already instantiated and no template exists at runtime any more.
By default, the object declaration, the method calling, the function calling, the variable declaration etc. are done at runtime.
However, c++ has the ability to make them at be done at compile-time, that's by using constexpr .
c++ :
int x = 3; constexpr int y = 789;
x is allocated and initialized at runtime.
y is allocated and initialized at compile-time.
c++ :
The constexpr variable must be initialized.
int a; // OK int b = 2; // OK constexpr int c = 5; // OK constexpr int d; // ERROR, constexpr variable must be initialized
c++ :
class my_class { }; int main() { constexpr auto obj1 = my_class{}; // OK constexpr my_class obj2{}; // OK constexpr my_class obj3; // ERROR, obj3 is not initialized. }
constexpr object is the same as constexpr variable in above example.
But just note that my_class obj3;
is considered that obj3 is not initialized, it can not
be constexpr,
and my_class
obj2{};
is considered that obj2 is initialized, it
can be constexpr.
Commonly, declaring an object means calling the constructor of the class.
If the object is expected to be constexpr, the constructor must be constexpr
too.
If the class has no user-defined constructor,
the class still has an
implicit-defined constructor by default,
that the constructor is constexpr.
Such as above example.
If the class has user-defined constructor, and you want the object creation
is constexpr,
then you must make the constructor declaration consexpr.
See c++ example:
class my_class { private: int __x; public: // constexpr constructor constexpr my_class(int x__): __x{x__} { } }; int main() { constexpr auto obj1 = my_class{33}; constexpr my_class obj2{44}; }
Just as the constexpr constructor,
the implicit-defined destructor is
constexpr by default.
And the user-defined destructor can be marked
constexpr too.
#include <iostream> class my_class { private: int __x; public: constexpr my_class(int x__): __x{x__} { } constexpr ~my_class() { } }; int main() { constexpr auto obj1 = my_class{3}; }
I said above, to make object creation constexpr, the constructor must be constexpr.
The same chain happens on destructor:
To make constexpr destructor work, the object
creation must be constexpr,
to make object creation constexpr, the constructor
must be constexpr.
So,
A working constexpr destructor requires constexpr constructor .
Note the words work and working I used here. I mean the constexpr object creation should work.
A method of a class can be constexpr too,
class my_class { public: constexpr int get() const { return 123; } }; int main() { constexpr auto obj = my_class{}; constexpr int x = obj.get(); std::cout << "x is " << x << std::endl; }
Note that a const object can not call a non-const method,
and constexpr
object is also const object,
so the method .get() must be marked as
const.
Please read day-11
>>>> const method calling each other
class my_class { public: constexpr int get() const // constexpr declaration { return 1234; } }; int main() { constexpr auto obj = my_class{}; int g = obj.get(); // non-constexpr calling }
Although the method .get() is declared constexpr, and the object obj is constexpr,
but the method calling obj.get();
is not constexpr.
If you insert runtime code inside the definition of body of the constexpr declaration, the code can not run at compile-time, then the calling will not be constexpr.
(Note that std::cout
can not be constexpr, std::cout is runtime code.)
#include <iostream> class my_class { public: constexpr int get() const { std::cout << "return value" << std::endl; return 123; } }; int main() { constexpr auto obj = my_class{}; int a = obj.get(); // OK constexpr int b = obj.get(); // ERROR, //method .get() can not be constexpr, // because it contains runtime code: std::cout. }
Putting runtime code (can not be constexpr) inside a definition body of related constexpr declaration is not an error, but the calling of it can not be constexpr.
Written on Dec 06, 2024
c++ std::exception:
std::cout.write(err.data(), err.size());
std::cout << std::endl;
caught:
=================================== # The c++ programming language. # # # # Join c++ Discord: yZcauUAUyC # # Deck # ===================================