C++ function declarations

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
albinopapa
Posts: 4370
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

C++ function declarations

Post by albinopapa » January 4th, 2022, 6:01 am

Code: Select all

template<rectangle RectType, math_vector VectorType, dimensions SizeType> 
[[nodiscard]] constexpr auto from_center( 
	VectorType const& position, 
	SizeType const& dimension )noexcept 
{
	using element_type = typename RectType::element_type;

	return from_center<RectType>(
		static_cast< element_type >( position.x ),
		static_cast< element_type >( position.y ),
		static_cast< element_type >( dimension.width ),
		static_cast< element_type >( dimension.height )
		);
}
That's a monstrosity. A far cry from what I was brought up on. In case any one wants to know what it all means, here goes.

First a list of features in use:
Template
Concepts
Attribute
Constexpr qualifier
Exception promise
Return type deduction

Templates allow you to pass in any type to a function in the case of templated functions or any class in the case of templated classes.

Concepts allow you to narrow down which types are allowed in those functions or classes. In this case I have three concepts; rectangle, math_vector and dimensions. They are custom concepts to restrict the types that can be accepted. rectangle is restricted to an instance of Rect<T>, math_vector is restricted to an instance of Vec2<T> or Vec3<T> and dimensions is restricted to any Size<T> where T can be any type. For instance, Rect<float>, Vec2<int> and Size<double> would all be accepted.

Attributes can give warnings or provide hints to the compiler. In this case, [[nodiscard]] tells the compiler to generate a warning IF you call this function and don't assign the result to a variable.

Constexpr tells the compiler that this function qualifies for compile time evaluation. It can run during runtime and might not be allowed to run at compile time depending on how it's evaluated during compilation.

The noexcept is a promise that no exceptions will be thrown in the function or any function that it calls. Almost any function qualifies to have the noexcept tag, but allocating memory or opening files and other activities are probably not viable candidates. If an exception is thrown, your program is terminated and no resources will be freed because no constructors will be called. It's left to the operating system to free any resources the program used.

Return type deduction using 'auto' helps shorten the signature and there are some caveats when using it. As far as I can tell, there are two rules for using auto by itself at the beginning of the signature.
1) If you split the declaration and definition into .h and .cpp files, the function must have a trailing return type:

Code: Select all

// declaration in header ( .h ) file.
auto do_something()->int;

// definition in source ( .cpp ) file.
auto do_something()->int
{
    // do stuff
    return 42;
}
If you put the definition inline with the signature, you do not need the trailing return type.
Like free or global functions, member functions of a class using auto without a trailing return type cannot be used before the definition of the called member function. The compiler needs to evaluate the called function first to determine it's return type before it can be used.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply