PrevUpHomeNext

day-20: c++ compile-time, constexpr


c++ compile-time

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:

c++ Variable

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.

c++ template

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.

constexpr

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++ constexpr variable

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++ constexpr object

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.

c++ constexpr constructor

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};
}

constexpr destructor

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.

constexpr method

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

constexpr declaration, non-constexpr calling

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.

constexpr does not guarantee compile-time

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

Back to index

Index

cpp/c++

c++ std::exception:

std::cout.write(err.data(), err.size());

std::cout << std::endl;

caught:

  ===================================
  #  The c++ programming language.  #
  #                                 #
  #  Join c++ Discord: yZcauUAUyC   #
  #  Deck                           #
  ===================================

Home: cppfx.xyz

K


PrevUpHomeNext