San-Diego C++ Meetup #57 “What can Class Template Policy Design do for your codebase?”

Hello all,

Short summary on the previous San Diego C++ meetup, the last one for 2023.

It took place on December 12th 2023.

The topic for the meetup was Class Template Policy based design. All based on the first chapter of Andrei’s Modern C++ Design book from 2001.

Here is a link to the meetup event.

Recording on our sdcppmu channel here:

Policy Based Class Design recording on sdcppmu YT channel

The talk goes over the first chapter of Andrei’s book highlighting the huge advantage of using this technique in your code. And in particular, it described the following items:

  1. Templates, specialization of Class Templates, functions, what is template-template parameters.
  2. Examples of how Policy design can improve readability, flexibility of your design.
  3. Static vs Dynamic dispatch/polymorphism.
  4. How to mix different, orthogonal policies
  5. How to mix policies with some dependencies (though this is not a recommended approach).
  6. Enrichment APIs and how Templates do not instantiate functions unless being used.
  7. Customizing structure with Policy Classes.
  8. Examples of Policy classes in the wild. ACE library, Standard library.

Next month will discuss chapter 2 that describes more of the important Template techniques.

That’s if for now.

Have a great holidays, hoping for a better 2024!

Kobi

San Diego C++ Meetup #56 hosting Šimon Tóth – “Patterns of interview solutions”

Hello all,

This post is about the latest San Diego C++ Meetup session, held on Tuesday, November 14 2023. It was a virtual meeting, recorded and uploaded to the sdcppmu Youtube channel. Here is the recording:

San Diego C++ Meetup #56 hosting Šimon Tóth – “Patterns of interview solutions”

Here is a link to the event on meetup.com

This time, we hosted Šimon Tóth who gave a wonderful talk named “Patterns of interview solutions”.

A bit on Šimon:

He can be found on the following Social media: linkedinhachyderm.iosubstackmedium and github.com .

Books on leanpub.com:

Summary of the content presented

The talk is divided to 2 parts. First part presented the available algorithms in C++. Including some from the ranges library. Total of 126 algorithms were bunched into categories and Šimon quickly went over the benefits of each category with some examples.

The second part presented couple interview-like questions and their respective Modern C++ solutions:

  1. Sum of distances to all nodes – Šimon demonstrated solving a problem while looking at it from different persoective.
  2. Longest palindromic substring – showing few ways to improve your algorithms using different methods.

In all of the above, Šimon is using ranges, algorithms and Modern C++ syntax and mechanism.

Hope you enjoy the recording!

Take care,

Kobi

Let’s embed it with C++! – San Diego Meetup #55 October 30th 2023

Hello everyone!

As usual, I’m providing a short summary to the previously held San Diego C++ Meetup session.

But before this, I’d like to promote the next, upcoming one – we are hosting Šimon Tóth that will present his talk – “Patterns of interview solutions“. This will happen on Tuesday, November 14th, 930am Pacific time. Looking forward!

The recording of the October meetup, named “Let’s embed it with C++” can be found here:

“Let’s embed it with C++” recording on youtube, sdcppmu channel.

Here, you can find the past event Link on the meetup.com page.

The original meetup session was scheduled to October 10th but I had an emergency travel to Israel supporting my family as I lost my nephew during the first few hours of October 7th war.

So what did we discussed about during this 1:30 hrs of this session?

The idea was to provide an overview, mostly for beginners to intermediate levels on how can we use Modern C++ features in Embedded environment. The talk was heavily inspired by this excellent book By Christopher Kormanyos:

I also started by mentioning 2 great talks. One from Dan Saks, cppcon2016 – extern c: Talking to C programmers about C++, and the second one from cppcon2022 – Erik Rainey, “Using C++14 in an Embedded ‘SuperLoop’ Firmware”.

High level topics discussed:

  • Using class types for encapsulations, organization of code, as well as namespaces
  • (No)Overhead demonstrated using various features like class types, constexpr, using templates to improve code generation.
  • Showing various code/options side by side using Compiler Explorer and the new CLion feature to “Show assembly” (what a great feature JetBrains!).
  • Discussing the subset of C++ that is useful for embedded. The various trade-offs using STL(Standard Template Library).
  • Using integral macros from “cstdint”. Thinking about portability of your code working with various OS and compiler vendors.
  • static_asserts, limits for more compile time evaluation.
  • Using std::array as a replacement to the C array.
  • Why STL algorithms are a good fit for your programs? How do they compare to raw loops, runtime speed and generated code.
  • The advantage of using User Defined string literals (one of my favorite features of the language!). How does it contribute to strongly typed elements with zero cost abstraction!
  • C++ Core guidelines, using std::span<> (and gsl:: library if you are working on <20 standard).
  • Demonstrating template integer sequences with Modern C++.

Conclusion is that C++ is more than suitable for embedded. You need to know how to use the language correctly, take advantage of templates when applicable, know STL well to avoid pitfalls!

That’s it for now. Hope this session is useful for various people at least as a good introductory session to various Modern C++ features.

Until next time, stay safe,

Kobi

San Diego C++ Meetup #53 – notes

Hello all!

We had a great night on Tuesday August 15. The San Diego C++ meetup #53 took place.

Here is the recording

San Diego C++ Meetup #53 recording

Here is a short summary of the topics and discussions we went through:

  1. Introducing the next month session – JFRog will introduce Conan 2.0. Chris McArthur will present it on September the 12th. Here is a link to the event on meetup.
  2. I introduced the new, 3rd edition of range-v3 booklet. You can find it here. This is by far one of the best and fun resource to use for learning range-v3. The material, content and quality is just premium. Run, don’t walk and purchase it. I love the printed edition. It’s a piece of art! In the meeting we went though the FizzBuzz example that can be found on walletfox website itself.
  3. Next, cppquiz #354 . std::exit() related.
  4. User Type categories – we discussed “Trivial and standard layout“, explaining the differences and why it is important to know about these categories.
  5. And finally, I presented a topic which I really like and close to my heart – properly writing multi-threading code. Well – there are many many things not mentioned in this 40 minute talk. But the goal was to bring some awareness on bad patterns or practices vs better, safer and maintainable patterns. We mentioned associating Mutex to its controller data, showed how Rust is doing it (in one slide), and eventually, went over POSA2Thread Safe Interface“.

Thank you for reading!

See you next time!

Kobi

Modern CMake Best Practices for Library Authors by Alex Reinking – San Diego C++ Meetup #52

Hello everyone,

I’ve been super busy at work hence the delay in this blog post that summarizes our 52nd San Diego C++ Meetup.

This time, we hosted a Qualcommer co-worker – Alex Reinking.

Alex is very knowledgeable in many fields and in specific, he likes build systems. We had an offline chat before he submitted the talk for the July session. We talked about CMake, FetchContent, Package managers and it was very clear to me that Alex would be great speaker in our meetup.

Here is the recording:

San Diego C++ Meetup recording – Alex Reinking talking about Modern CMake

Alex started by taking us through the general idea of CMake as a build generator and also mentioned its popularity in the community.

Few important bullet points and take away:

  1. Under the hood, Package managers do more that you realize. Like patching code and similar.
  2. As a library, we would like to provide the users the best experience when using our library with CMake.
  3. Alex has a very nice demo posted here: alexreinking/sdcppmu-diffuse. Building on Linux and MSVC with Emscripten targeting WebAssembly(Linux)/SDL(Windows).
  4. Always use the latest CMake. This is something that I like in CLion which is usually bundled with the latest, or almost latest CMake.
  5. CMake’s find_package() is the one true way to locate dependencies.
  6. FetchContent is nice but it will clutter your CMake “env”, unless upstream project is written well enough.
  7. Halide (see Alex’s Bio) has CMake helper functions like “add_halide_generator“, “add_halide_library“) – a generator that must run on the host system, even when cross compilation is involved.
  8. Alex walks us through the path of getting your library “FetchContent” friendly for consumers.
  9. Interesting discussion on Why we should not create 2 targets (shared and static for example).
  10. Why not GLOB for sources.
  11. Discussion on what to place and NOT to place in your CMakeLists.txt. For example – compile options – probably should go into Presets.
  12. Other CMake related constructs that were new to me: ALIAS for add-Library, BASE_DIRS + target_sources, GenerateExportHeader, CMakeDependentOption, CMakePackageConfigHelpers, configure_package_config_file, write_basic_package_version_file.

More information can be found in the recording.

Thank you!

Kobi


Abstract
In this talk, we will discuss the best practices as of the latest CMake version for writing C and C++ libraries that are easy for everyone to consume. We will build a toy application that demonstrates switching between static and shared library types, dependency management, creating accurate CMake config packages, and cross-compilation involving code generators. We will see how writing CMake lists that are minimal and declarative leads to more correct and maintainable builds.

Bio
Alex is a research scientist at Qualcomm Compiler Labs. He got his Ph.D. in Programming Languages from UC Berkeley in 2022. Since 2020, Alex has served as an open-source maintainer for Halide, a popular DSL for optimizing image and tensor processing; in this capacity, he has overhauled the build system, CI infrastructure, and the release process. Alex has contributed build system improvements to prominent open-source projects, including WABT, tinyxml2, and Herb Sutter’s cppfront, and has found and fixed large CMake bugs. His blog page: https://alexreinking.com

Link to the event

Ben Deane – San Diego C++ Meetup! June 13 2023 #51

Hello all,

It was yet another exciting night this time hosting Ben Deane!

His talk named “Applicative – the Forgotten Functional Pattern

Here is the recording:

Ben is a great speaker and he loves Functional programming 🙂

First – the Abstract:

Abstract

Monads get all the press. Functors are often presented as a prerequisite to monads. Applicative (functor) almost never gets mentioned. But it’s massively useful – to the point where a lot of the time when we think about a “monadic interface” what we really want is an applicative interface.
This talk will put applicative in the limelight, showing how it works and why it’s so powerful, with lots of examples grounded in code; there are no category theory diagrams in this talk. Attendees will come away with a solid understanding of the applicative pattern and its many uses. And as a byproduct, their opinions of monads will probably change too.
Optionals. Expected. Ranges. Futures. Parsing. Validation. Error Handling. Transforms. Functions themselves. These are all examples where thinking in terms of applicatives (and importantly, NOT just reaching for “a monadic interface”) helps us write simpler, more composable code. If you’re kind of fuzzy about functors and monads, what’s missing is probably the third piece of the puzzle: applicative.

Summary

I’d classify this talk as intermediate++. Ben mentioned many concepts like optional, ranges, Monads and std::expected just to name a few.

Throughout the talk, Ben presents Haskell syntax and C++. The Haskell part is easy to grok though if you are seeing this syntax for the first time, you might want to pause the recording and make sure you understand it since the sub-sequence slides will build on top of it. There are also some heavy generic programming slides that might need more attention when you go through the recording. No spoilers here on the conclusion and the take away (regarding Monads vs Applicative)

Overall I learned a ton from this talk and have some homework to go and explore more on this domain.

We have an incredible future ahead of us in terms of new syntax and new language and library capabilities.

I’d end with a meme 😉

About BEN DEANE

Principal Software Engineer at Intel
Ben has been programming in C++ for this whole millennium. He spent just over 20 years in the games industry working for companies like EA and Blizzard; many of the games he worked on used to be fondly remembered but now he’s accepted that they are probably mostly forgotten. After getting more interested in modern C++, in the teens he started giving internal company talks and then talks at various conferences, spreading ideas about types, algorithms and declarative and functional techniques. In 2018 he left the games industry and worked in finance for a short spell, writing high-frequency trading platforms using the most modern C++ that compilers could support. Now he is a Principal Software Engineer at Intel where he puts monads inside your CPU.

Thank you!

Kobi

YACRB – Yet Another CoRoutines Blog

Based on a true story from the San Diego C++ Meetup #46 1/2023

After our Jan 2023 virtual meeting I wanted to summarize all the cool stuff we learned during the session. This is the short version of the talk that I (Kobi) presented on Tuesday, Jan 17 2023.

First, I’d like to have few shout outs to few people that inspired this talk.

The first one, is Pablo Arias. Pablo had a 3 parts Coroutines blog post that explains how to use C++20 Coroutines and Linux Kernel’s feature io_uring. First part can be found here. It includes link to the source and discussion on reddit. This blog post is written so well that it helped me to finally understand how Coroutines work and I wanted to present it to the members of the San Diego C++ Meetup.

Next, I’d like to thank Rainer Grimm from the modernescpp blog. Rainer has many books that I mentioned during the San Diego C++ sessions, he has Educative.io class and he is a known speaker in many C++ conferences. His C++20 Coroutines blog posts are very helpful.

Coroutines change the way you write Parallel and Multi-threaded code, to the better IMO. Once this topic is well understood, you will want to use it in your code base as it’d simplify many constructs.

I’d like to touch upon few main issues when it comes to Coroutines. Why this is so hard?

  1. First, it is a complicated domain. Async, MT and similar are usually harder to reason about.
  2. There are new keywords that we need to learn and understand how to use.
  3. There is a new Coroutines API. How do we use it? What do we need implement? do we need to inherit? what is the new contract between different pieces of the app when it comes to Coroutines?
  4. Compiler magic. The compiler does a lot of things under the hood and we need to be aware of the various things that are happening. We usually know that compiler might generate special functions for us (e.g. copy constructor) but Coroutines is a new level of “compiler magic”.
  5. When Coroutine function is running, what is the thread context? what is the thread context of “Awaitables”? what happens when we resume? which thread is being used here? These are real questions that we need to answer to fully understand this domain. The regular execution flow is very different from what we are used to see before, even when threads are involved.
  6. C++20 gave us “the assembly of Coroutines”. This is how I name it. During the meetup session i mentioned that in his latest book, Bjarne does not recommend writing your own Coroutines boilerplate code and use libraries instead. During the talk, I used the low-level Coroutines API.

I presented the following from modernescpp:

This is a good image illustrating the new flow of function calls.

There are numerous amount of blog posts out there that explain what is a Coroutine function/object/frame. For our purpose in this post, I’ll touch upon few elements but will not cover everything under the sun when it comes to Coroutines. The goal is for the readers to have basic++ knowledge that jump-start them to work on more complicated constructs.

What does qualify a function to be a coroutine?

It has one or more specific keywords for example:

  • co_await – suspend and resume execution of the function while keeping the context (think stack) intact!
  • co_return – return results from Coroutine frame/function.
  • co_yield – supports generator functions.

coroutines proposal N4402 describes design goals.

C++20 Coroutines framework includes many functions to support various use case and it is highly customizable. Main parts:

  • Coroutine handle – this is your handle to the Coroutine context.
  • promise object – think about it as a way to communicate results back to a waiter.
  • Coroutine frame – holds the state of the Coroutine function.

Task and Promise

Promise provides result or exception. It is the result of the work done in the Coroutine function.

A pseudo code that represent a possible promise struct, residing inside a “Task” will look like the following:

Promise is highly customizable. User can control whether:

  • Coroutine should be suspended before it runs (initial_suspend), or before it ends (final_suspend).
  • unhandled_exception – invoked when uncaught exception happens.
  • get_return_object – returns, constructs the Coroutine object itself, many will name it “Task”.
  • return_value – This is “magically” invoked by compiler-generated code when we write something like co_return val;
  • yield_value – related to generators when we invoke co_yield val;

get_return_object() mentioned above is super important. It is creating a “Task” instance. Promise type is nested inside a Task.

Promise will communicate the results (or void) using the return_value/return_void/yield_value.

Awaitable

Awaitables are structs/classes that we, the author of the code/framework will write.

An Awaitable, is a type that you co_await on its instance.

So how does a birds-view Coroutine structure in your program would look like?

Here is a pseudo code of Task with a nested promise, an awaitable with operator co_await() and finally, a Coroutine function named “func”. This Coroutine function returns a “Task” as its return value, and will co_await on 2 different awaitables. It returns result using co_return.

Coroutine Handle

This is a super important element that enabled the caller to access the Coroutine frame/API – for example resuming a suspended Coroutine.

In the above code snippets, you’d find the handle in class Task – which is mapped to a Coroutine object. In the following code snippets, you’d also find this handle being passed as a parameter to the Awaiter::await_suspend(handle) function.

Coroutine Frame

This is internal, i.e. not really visible to us, authors of the code, most likely a compiler’s heap allocated state.

It containes a promise object with all the Application related context, aka my Application business logic.

Example – Coroutine with UDP server and io_uring Example

As mentioned, this part was heavily inspired by Pablo Arias blog post.

In this exercise we will demonstrate how we can combine Coroutines with file reading/writing as well as working with networking protocols.

In the meetup recording you can find the conan 1.x configuration, using crc_cpp and fmt.

Demonstrating Synchronous first

Before we jump into demonstrating how coroutines + io_uring makes our life easier, let’s show the synchronous part first.

In the above we show a udp_connection runs a blocking read() function. Once it is done, it will populate a vector and compute CRC16 to show some “work done” (CRC is a 3rdparty library).

udp_connection::read() would look like this:

Pretty simple and straight forward. Compute CRC16 is just looping over the buffer and computing the value. It is omitted here for brevity but the information can be found on meetup slidedeck (and my github.com).

Struct Result is just a simple struct to aggregate and collect information that will be eventually printed to screen:

Here is the complete “main loop” for the Sync example:

I’m just showing 2 connections but you can easily extrapolate it to be >2.

Enter Coroutines and Linux io_uring

First let’s discuss io_uring. The simplest way to think about it, is submitting a request to the kernel to do it on user-space behalf, and then gathering results back when work is done and results are ready:

Once we have this concept understood, we will tie it into Coroutines using the following flow:

The part where we Read UDP will be offloaded using Coroutines mechanism in conjunction with another Coroutine piece that will write results into files. For each context, the UDP read and File Write operations would be 2 different awaitables triggered by the same Coroutine frame.

The nice part about Coroutines is that the function “launching” these awaitable will be suspended and resumed while the entire function’s context stays “intact”. This feels very natural when reading the code. There are no messy state machines and complex locking code. It’s all abstracted out using the Coroutine framework.

The following diagram depict how Coroutine frames would look like. A Coroutine frame is mapped here to a function names readUdpWriteFileAsync().

There are couple arrows going out from the frame into functions. Think about these functions as awaitables.

The diagram shows 2 frames. Reason is that we’d have the main() function looping over 2 connections. Each connection will invoke the Coroutine function, creating a whole separate Coroutine frame and context.

When we invoke the read_udp_socket inside readUdpWriteFileAsync() Coroutine function, it would be suspended so we can continue our main() iteration moving to the next udp_connection, this is while the previous one is “taking its time” reading from a socket in a separate thread.

This is the true exciting moment of Coroutines. I have a loop calling a function, this function will shoot an async operation, running on some thread (details below) doing its thing while I continue looping and handling the next iteration. When I need to go back to _a_ Coroutine frame, it will be there waiting for me with the entire stack context intact!

Let’s take a look at main()

I just create 2 UDP connections objects and you can easily extend it to >2. No socket activity here, just initialized UDP class type objects.

The following code is important. It will actually trigger the creation of the Coroutine frames. 2 in our example. Each time we invoke readUdpWriteFileAsync(), a Coroutine frames created, returning a “Task” class instance. More on “Task” below. We just keep the tasks in a vector so we can use each later.

liburing is used here to abstract out some io_uring boilerplate code.

Pablo had a nice liburing wrapper that I’m going to use here. It’s a simple wrapper over io_uring handle, implementing RAII (init, destroy). This is going to be very handy when interacting with io_uring via liburing library.

Promise & Task

After introducing the concept and some of the non-coroutine framework, let’s delve into the actual Coroutine-framework details.

We will start with defining the “Task” class type:

There is an inner struct names promise_type. As mentioned above, promise would include my business logic and you can see class data member named result.

Few important functions that I implemented (there is also the inheritance way btw).

  • get_current_object – Instantiating and returning of a Task. Just calling it constructor with this argument.
  • I don’t care about exceptions. It’s an empty method here.
  • return_value – will be “magically” invoked by compiler-generated code. My function definition is going to set the incoming parameter to my internal data member.
  • Don’t care about initial_suspend/final_suspend. I’m returning suspend_never which means – do not suspend at init/cleanup points.

Let’s zoom out and see what else we have inside class Task:

struct promise is collapsed as we’ve already discussed it.

Task has a constructor that takes promise* parameter. No surprises here since promise_type‘s get_return_object() returns Task(this).

The Coroutine handle is obtained from promise. The Coroutine handle is our mechanism to control the Coroutine ‘sflow. If we hold a Coroutine handle, we can, for example, check if the Coroutine is done() processing or we can resume() the Coroutine. We use this handle few times in our application.

Task has one important data member. The Coroutine handle! This is our opaque handle to the Coroutine frame/context.

  • get_result() – will return the (final business logic) result, residing inside the promise_type.
  • done() – will return true if the Coroutine is done executing. Essentially when we exit from the Coroutine function/frame. In our case existing readUdpWriteFileAsync().
  • Destructor destroys the handle.

The awaitables

We have 2 awaitables.

  1. For UDP read
  2. For writing data to files on disk.

Here is how it would look like:

The Coroutine function/frame is readUdpWriteFileAsync().

  • When we want to co_await on the UDP read part we will call co_await read_udp_socket. A thread will be created and used to fulfill and run this context. When we are done, we are going to resume the suspended frame. We use the Coroutine handle to resume the suspended Coroutine. read_udp_socket is our first awaitable.
  • When this specific frame instance is resumed, we will interact with io_uring framework, submitting job to the kernel to execute. Here we don’t need to worry about any user space threads since this job is executed in the context of kernel space. We just need to collect the results when we are ready. When results are ready, we will resume the suspended frame, running it to completion. Task will be done here.

Coroutine function readUdpWriteFileAsync

Here is the implementation of our Coroutine function with 2 Awaitables.

First Awaitable is read_udp_socket(). You can notice the special keyword “co_await”. More details to follow.

Next, we create a file and move to the next Awaitable: write_file_awaitable(). co_await new C++20 keyword is also used here.

At the end of the frame, we return the result using co_return keyword.

When running the applications, lots of stuff happening by a compiler-generated code. For example, when we call the Coroutine function, a Task::promise_type::get_return_object() function is immediately invoked. A debugger is a handy tool here to view the stack-trace. You’ll notice some strange jumps of the debugger as if the Task function readUdpWriteFileAsync() is “exiting” but it’s not. It’s just the debugger showing that a Task object was created and it will jump “all over the place”.

To assist us with collecting results AND holding the coroutine_handle, I will create a simple struct to aggregate both:

Awaitable read_udp_socket

Let’s zoom-in into our first Awaitable. It’s a class type with operator co_await:

operator co_await() is a new C++20 special construct. We need to return an “Awaitable” type instance. What is Awaitable? It’s a type with a specific interface that we need to implement. Note the return value of operator co_await: it’s the Awaiter struct instance initialized with udp_. What interface do we have in Awaitable?

  • await_ready – we return false. We are not ready yet! and work needs to be done. We need the Task/frame to be suspended!
  • await_suspend – An customization point before we suspend the “outer Task/frame”. We keep the coroutine_handle by assigning it to some structure as we will need it soon! we need the handle to tell the Task/frame “continue/resume”. The handle is our way to control the flow of the Task!

So the idea is simple. The outer Task calls co_await on the Awaitable. Operator co_await kicks in. We keep the coroutine_handle before we suspend the Task and executing the work on a dedicated thread. Remember, now, the outer Task is suspended! The main loop will continue with the next UDP connection instantiation.

When we resume the Awaitable, await_resume() is invoked on this Awaitable instance, and the result is returned as the value. If you set a breakpoint at Awaiter::await_resume() you will see how invoking resume() on the coroutine_handle will call some compiler generated symbol which will invoke Awaiter::await_resume(). It’s all can be viewed as part of the gdb stacktrace. Here is a typical example:

You probably noticed the function readSync(). This function does a simple blocking UDP read + CRC16 check. When it’s done, it takes the coroutine_handle that was passed as an argument and call resume().

Writing to disk using io_uring

This is the second Awaitable. Unlike the UDP one, this does not run on std::thread context, but using Kernel threads instead. Here is a helper struct named write_ctx. We are going to use it as an opaque data/cookie to the Kernel and receive it back later(think cookie).

The struct has similar idea as the UDP’s one. It includes std::coroutine_handle<void> and some result (status_code).

And here is the full write_file_awaitable Awaitable class type with its internal operator co_await().

The constructor of this Awaitable is obtaining io_uring_sqe which is a token corresponding to the requested job to be done by the Kernel on our behalf. We request to write a chunk of memory to file using this token. This is the first part where the instance of the Awaitable is being created.

Now the co_await operator kicks in. Same idea as UDP. We need to implement few interface functions.

  • await_ready() – no, we are not ready, please suspend the Task.
  • await_suspend() – customization point before the Task is suspended. We cache the handle and we tell the Kernel – please associate the following piece of data with the token. Remember, without this coroutine_handle we cannot resume when we are done with our file write! When the Kernel is done performing the requested job, writing to file in our case, it would provide us back the opaque data that we provide to it when calling io_uring_sqe_set_data(). Finally, we call io_uring_submit() to get this whole io_uring process going.
  • await_resume() – when the Task is resumed, the status_code is returned back. The status_code in this example correspond to success/failure of writing into file.

io_uring results – processing logic

It’s time to gather results and process it.

Remember that we had a vector of “Tasks”?

These Tasks are actually mapped to our Coroutine functions.

When we invoked the Coroutine function, we got a “Task” back as a return value and “push_back” it to our std::vector<Tasks>.

Task class type has a function named “done“. This function will return the Coroutine handle’s “done” state. If it’s true, we are done with the Coroutine. Either we have all awaitables done or exception propagated. The important part is that the function is done and we can query the handle in order to figure it out.

Function all_done just iterates over the vector and ask if we are done.

When we are all done, we just print something. This is a simple final “processing” and obviously real-life logic would do more here.

But inside the while loop, there is a special call to consumeCQEntriesBlocking(). Let’s take a look and discuss the last part of this flow.

When we submit a request to the Kernel via io_uring framework, at some point of time, we would like to retrieve the result (or error if such returned back).

io_uring_submit_and_wait() is a liburing function to block if queue is empty and if we have at least 1 completed entry waiting for us, we will return from the function and process it.

This is what consumeCQEntries() function is doing. The coroutine magic part is the line that invokes resume() on the handle.

When we submitted our request, we also submitted a “cookie”. An opaque data that we are now retrieving back! We static_cast<> it and now have access to the status_code as well as to the Coroutine handle! This is a key element for us to control the Coroutine.

We can now resume the Coroutine and the function readUdpWriteFileAsync() will continue to run. In our case will complete and exit using the co_return keyword. It will return the Result struct instance.

Handle’s done() is now going to return us “true”.

When we call .resume() and the Coroutine continues to run, it’d run on the “main” thread. You can think about it as the main thread is borrowed to execute the remaining code in the Coroutine function all the way to the co_return statement.

Summary

The above demonstrated single Coroutine function returning a “Task” class type, with 2 Awaitables – “UDP socket receive” and “file write” using Linux io_uring. We showed how to use Coroutine handle to obtain info on the Coroutine frame as well as control the actual flow of the program.

There is a big advantage of having the context of the frame kept intact, valid, in one location while all kinds of jobs are triggered, suspended and resumed without any need for synchronization. In traditional multi-threading/multitasking you’d need synchronization primitives in order to achieve the same.

Thank you for reading!

Kobi

San Diego C++ Meetup May 16 2023 – #50 – C++ Horizons by Bryce Adelstein Lelbach

Hello everyone!

Our San Diego C++ meetup 50th anniversary was celebrated hosting Bryce Adelstein Lelbach – a very known persona in the C++ community and the chair of the Standard C++ Library Evolution group.

Bryce gave a talk on C++ future, cutting edge features. Here is the list of the 3 items presented.

  • Reflection/injection – facilities for extracting information from the program, performing compile-time computations based on that information, and injecting new program entities based on those computations.
  • Pattern matching – a new expressive selection mechanism that matches values against patterns and binds variables when matches are successful.
  • Senders – a framework for asynchronous programming that enables us to write generic code that can run on any type of execution resource, from a single thread to a cluster of GPUs.

Bryce believes that in the next decade, the above three major new C++ features will reshape how we write C++ code. This came with a lot of very interesting examples.

Here is the recording in San Diego C++ Meetup’s YouTube channel:

Bryce Bio:

Bryce Adelstein Lelbach has spent over a decade developing programming languages and software libraries. He is a Principal Architect at NVIDIA, where he leads programming language standardization efforts and drives the technical roadmap for NVIDIA’s HPC and Quantum compilers and libraries.

Bryce is passionate about C++ and is one of the leaders of the C++ community. He is the chair of INCITS/PL22, the US standards committee for programming languages and the Standard C++ Library Evolution group. He also serves as editor for the INCITS Inclusive Terminology Guidelines.

Bryce served as the program chair for the C++Now and CppCon conferences for many years. On the C++ Committee, he has personally worked on concurrency primitives, parallel algorithms, executors, and multidimensional arrays. He is one of the founding developers of the HPX parallel runtime system.


This is for this month. Hope you’ll enjoy this excellent recording.

Kobi

San Diego C++ Meetup Apr 11 2023 – #49

Summary of the last San Diego C++ Meetup – held on April 11 2023. This was our 49th meeting since inception on March 12 2019.

Sorry again for the delay posting this summary. I had some technical issues uploading the recording last week and finally found some time to write the summary.

Recording can be found here:

San Diego C++ meetup recording – April 11 2023

Discussion points:

C++Quiz.

Three fun C++Quiz questions. One related to UB when writing to const, another one related to copies made when using range for loop with auto and the last one was related to references and alias.

Walletfox slide – C++ Functional programming

I really love Walletfox (Ruzena Gurkaynak) work. The website has FP slides, Ranges-v3 booklet that can be purchased online (ebook + printed) which is highly recommended!

We discussed one slide related to Curring and “Partial” (like bind1st and similar but modern style).

Why I cannot emplace_back

This came up during code review. I was demonstrating the differences between vector::emplace_back of a simple struct vs unique_ptr<> “hosting” this struct. More info in the recording.

Using std::tie in C++

I love C++17 [structured, binding] but when I have no choice or when it falls short, I use std::tie. Also std::tie has other few applications that makes it easy to write code. I demonstrated few.

PImpl pattern

The final course was PImpl pattern. One of my favorite and a very useful pattern. We went through the definitions in cppreference, and mostly went over Herb’s GOTW #100/101.

That’s it for April meeting summary.

Thank you!

Kobi

San Diego C++ Meetup Mar 21 2023 – #48

Amir in his Daily life

Yet another apology on the delay in posting the summary of the latest San Diego C++ Meetup. Super busy at work.

It’s finally Friday night and I have some time to sit down and write the summary.

4 years. Total of 48 meeting. Missed just one session, March 2020 when COVID started. I was not ready yet for the whole virtual meeting thing and here we are today. 3 years later – all virtual.

The first year was in person, we were just building up the group in San Diego. XCOM-LABS were generous enough to provide the space, first in La Jolla UTC and then Miramar area – yeah, where you can find Top-Gun 🙂

For the past 3 years, Qualcomm is sponsoring (paying the meetup.com fees) this group, especially my VP, Charles B which is a big supporter.

For meeting #48, we had Amir Kirsh. This is not Amir’s first appearance in the group and we really like his talks.

You can find the meetup page here, the YouTube channel has many past recording including the latest one with Amir.

Talk abstracts:

C++ Incidental Explorations by Amir Kirsh
This talk will guide us through some interesting discussions of C++ using questions from StackOverflow for inspiration. With these questions as our starting point, we will try to learn C++, explore some of the corners of the language, get lost down a few rabbit holes, and become familiar with some topics usually reserved for “language lawyers”. We finish by exploring whether, and how, ChatGPT might help with writing C++ in the future.

Summary: This was a unique session. Exploring Stackoverflow C++ questions, discussing about various ways to analyze C++ questions, searching for unique questions and finally, we had a nice discussion on GPT, ChatGPT and how this can help us, especially in the context of programming and C++.

Among the many topics covered, we discussed Chrono library, auto as an optimization opportunity, overload resolution, const RValue – is it useful?, Iterator class, Reverse Iterator tricks, UB in accessing unwound stack address, — > “operator” , sorting, class owning a member of its own type and many more. All in just 90 minutes!

Amir’s Bio: Amir Kirsh is a Lecturer at the Academic College of Tel-Aviv-Yaffo and a Visiting Lecturer at Stony Brook University, as well as Developer Advocate at Incredibuild. Amir also serves as one of the organizers of the CoreCpp meetup group and CoreCpp conference in Tel-Aviv, as well as a member of the Israeli ISO C++ National Body.

Thank you Amir! and see you all next time!

Kobi

San Diego C++ Meetup Feb 15 2023 – #47

Apologize about the delay in posting this. Here are the minutes from the last San Diego C++ Meetup, held on Wed Feb 15 2023 5PM Pacific time. Thank you everyone for joining!

The meetup was recorded and uploaded to sdcppmu YouTube channel here:

San Diego C++ Meetup #74 Youtube recording

So what did we have in this meeting?

First – I presented an interesting Req in Qualcomm ML/AI Cloud group. The req number is 3046377 and you can find it on Qualcomm jobs website.

Next, we went over 4 cppquiz questions. The idea here, besides fun, is to learn new elements and constructs in the language. The cppquiz questions were 333,312,318 and 319. We learned about post increment, struct/class inheritance and members visibility, operator void(), casting to void and finally, ternary operator with class inheritance and implicit conversion using implicit constructor.

Next, we discussed the following use case how-to-prevent-stdfunction-to-bool-conversion-in-c-function-overloading . We demonstrated usage of C++20 concepts (std::invocable) as well as enable_if_t.

The next topic is a very interesting one. Polymorphic arrays pitfalls. segmentation-fault-in-operator-delete . It talks about allocating an array of a derived class type and assigning it to a base class pointer. When we do pointer arithmetic, it’s all messed up, and obviously delete []p will also fail. A good picture of what’s going on can be found here:

polymorphic array done wrong

We demonstrated few alternatives. For example, std::vector<p*> would be a good approach and instead would look like:

Vector polymorphic done right

More info and details in the actual recording.

The last one was about template instantiation, RValue binding to const& vs non const& and the implications. Also mentioned (again) implicit conversion in the same context. The details can be found here: why-does-removing-const-from-the-constructor-parameter-stop-the-class-from-being-instantiated . The actual code is here:

What, The Heck

Long story short, when you have const& the compiler can create temp of What<int> with the which is passed, so it tries to instantiate What<T>(The) and check if this Heck(const What<int>&) can be used . If there is no const, you cannot do such RValue/temp binding hence no need to instantiate What<T>. Though we did mention that Heck(The) constructor will be a better match anyway since it does not require any user defined conversion to happen.

That’s it for this #47 session of sdcppmu. See you next month with a special guest. Will be announced soon!

San Diego C++ Meetup Hosting Amir Kirs – To Move Or Not To Move!

Hello everyone!

Tonight (Dec 6 2022) we hosted Amir Kirsh from Incredibuild.

Amir went over the various use cases of using std::move, also highlighting std::forward usage, various pitfalls and he provided us with good set of guidelines on when to use and not to use std::move.

Highly recommended!

Here is the recording (can be found in Youtube channel sdcppmu)

Our event link on meetup.com can found here: San Diego C++ Meetup

Amit Kirsh

San Diego C++ Meetup – #44 – RxCpp and Boost.Asio

Today, Monday, November 14, we had our #44 San Diego C++ Meetup.

Unfortunately, there seem to have some issues in the posted link on meetup and many could not attend. Giant apology on this one. Not sure what happened and how but would pay extra attention next time (Dec 2022 here I come …).

Tonight, we discussed few interesting C++ Quiz questions, talked about RxCpp book from packt –

And also talked about Boost.Asio from the excellent Boost book:

here is the recording:

Enjoy!

Kobi

Modern C++ Coding Standard by Marcus Tomlinson – book review

By Yacob (Kobi) Cohen-Arazi

I have this habit of buying books. Like tons of books. Ask my wife, she’ll tell you. I think at that point she gave up.

I like to read what others think about the industry, about a specific domain. How do people see programming (especially C++) and technology from their own perspective.

So sometimes, I get to buy some not-so-familiar-books. This time it was “Modern C++ Coding Standards” by Marcus Tomlinson.

In the book, Marcus is saying that he wanted to share a handful of simple guidelines and best practices that he has been using in producing solid C++ projects over the past few years. And I do think he succeeded in this goal.

I’d start off by stating that the book is short. Easy to read in just couple hours. Not a lot of code snippets, so it’s pretty light. Very easy to quickly digest.

The book starts with one of the best features of C++ – RAII – C++ resource management mechanism. It explains the benefits of this important feature, not only in the context of Memory but also in the context of general resource management and cleanups at the end of a scope.

There are total of 3 parts in the book. Each has few chapters.

Part one (Modern C++ Coding Standards), Chapter One talks about how headers should be written. Couple things that I’m kinda disagreeing on, or at least on the fence:

  1. #pragma once – I’m leaning towards what the standard dictates vs the “less typing” approach. Yes, most likely you are working with a compiler that would have no issues with “#pragma once” but again – it’s not standard (yet?).
  2. Defining special member functions even though you do not have to. For example destructors. Even writing explicit =delete when not needed is something that I would not advise or at least I do not do it in my own code base.

Other than these two, there are plenty of well written points that I’m 100% on board with. I’m not going to list it here since the list is kinda big for a short blog post but I do suggest you go over it and see if you are aligned with each. I believe most of us would be.

Chapter two of the same Part One talks about organizing your cpp files. Again, plenty of good rules that I found very easy to read and digest. I believe most of the readers would find this part useful as well. As in the previous chapter, I have disagreement with one item – organizing the include headers. I’m in the camp of organizing the headers from the more general ones to the more specific ones. For example – your OS headers, then standard lib, 3rd party, your project. I find this order to be less disruptive and pretty solid when it comes to possible errors coming from your own project or 3rdparty headers.

Chapter three talks about Application Sources. Basically where your main() function lives. Lots of good suggestions like using std::future when appropriate, how to use std::async and similar. Just a reminder – the book is not going into details of the “why” but rather stays on the “trust me, you should do what I say/preach”. The bullets on auto, smart pointers and typedef vs “using” vs #define is spot-on.

Part Two is named “Language Agnostic Best Practices”. Chapter Four includes a set of very well written recommendations on how to construct your build system, automating the boring stuff (also great book … on Python), warning levels, static analyzer, version control, formatting etc… I felt like this is a really good list that should be applied to any Software project, regardless the programming language.

Part Three talks about “Templates & Compile-Time Programming”. Chapter five provides a short intro into Templates. I was pleasantly surprised to see C++20 code in this chapter. I.e. seeing concepts described as an advantage when used with Templates. Same warm feeling seeing C++20 related Lambda syntax. Overall, a very good Template introduction squeezed into just a few pages. While there are almost no real recommendations here in terms of coding standards but rather a C++ Class/Function Templates overview, I did find one good recommendation – Avoid specialization function templates and prefer overloading. Good one!

Chapter Six describes Template parameters. Again, not many recommendations but rather a good, concise overview on Template parameters. It covers Type Template parameters and also Non type as well as Template Template Parameters.

Chapter Seven, named “Beyond Templates” explains compile-time programming. It’s a very short chapter that describes the main idea behind constexpr and consteval (again, nice to see C++20 syntax).

The last part of the book provides an excellent summary of the points touched upon in the book. Basically, one can skip the entire first 86 pages and jump directly into the summary and just read, absorb and adapt (modulo the few disagreements that I and maybe others might have).

Overall, an affordably priced book, short (less than 100 pages long) but has good set of recommendations that should work for most, if not all, of us, Modern C++ programmers.

And Marcus – if you are reading this – great job! 🙂

Use case of utilizing std::set instead of std::map

Some time back I reviewed code that had the following design and data structure:

Now, the above is a struct but just imagine it could be a class with private/public sections, a beefy interface and data members.

The author(s) of the code wanted to place it in some data structure that can help retrieve an “Object” using a given “ID”. So they picked the following approach:

Pretty standard data structure. A {key, value} pair where the “key” is the “ID” of the “Object” and the “value” is the “Object” itself. This is not the first time I see such pattern. It is actually quite common in various code trees.

While looking at this piece of code I wonder, can we do better? The “ID” is part of the “Object”, and the requirements are to be able to insert/find values using std::map(*). The “Object”s are ordered by “ID”. My question is – Why do we need to repeat “ID” as a “Key” ?

Before we move forward, let’s compute the current cost:

This prints “sizeof pair 48, object 40, string 32” which means we pay an extra 8 bytes for storing an integer as the “ID”/”Key”. The same integer that is already stored in “Object”.

So the immediate thought is “yes“. We can do better. What if we eliminate the need for a separate “Key” and store the “Object”s in a similar container, that provides us the same requirements/performance(O(x) wise) but with smaller memory footprints?

We have something like this. It is called std::set<> and it has very similar characteristics to std::map<>. std::map<> stores std::pair<T1,T2>. It contains 2 types. std::set<> stores a single type.

So let’s give it a shot:

And we would like to have the same idea. We’d like to lookup number “5”. But std::set<> does not have a subscript operator (“[]”). It does however have “find()” function instead:

There are couple things we need to straighten out before we open the champagne.

First, by default, std::set<> requires less (“<“) operator to be defined for the stored objects. The compiler does not know how to compare “Object”s. We need to teach it. We can pass a compare function, we can use lambda or, we can just implement a simple member function that will help us to compare Objects by IDs.

This is basically fixing the major missing part. Remember that with std::map<> we had simple “int” as a “Key” and the compiler is very capable of generating code to compare “int”s. But not for “Object”s.

There is some wart here that requires discussion. If we want to write something like:

We need to be able to convert an integer to an “Object”. We can do it using a conversion constructor:

Notice the comment. We cannot make it explicit. In most cases, conversion constructor should be marked explicit, but if you actually need the conversion, you would have to pay this trade off. Otherwise, you’d need to write something less “natural” e.g.:

In my opinion this is a trade off that we would need to pay. Unless there are other sane options. For example I could think about having this non-explicit constructor in private section and having a get() friend function accessing it but I’m not sure this worth the effort.

That’s it. I saved you 8 bytes per entry. Keep the change and thank me later!

(*) std::map is probably implemented as a Red-Black Tree with log(N) to find something and O(1) to (re)balance it

Edit: September 29 2022

I recently realized that I could use Heterogeneous lookup and solve the issue I described with the find function. Here is the example:

And now, I can caall my find function in a very natural way:

Bingo!

Templates, Linking and everything in between

Last weekend, San Diego C++ Meetup hosted Andreas Fertig. Andreas presented his excellent talk on “C++ Templates”.

During his talk, one of the attendees asked a question that many, if not all, C++ programmers had asked at least once in their early life as C++ programmers. In this post, I hope it would provide answers to anyone that bumped into this issue before, and for those that haven’t yet 🙂

And the questions goes something like this.

While compiling and linking my C++ application, which happens to use templates, I’m getting a linker error.

To demonstrate this issue here is a simple example:

hpp file (include guard omitted):

Plus, here is a cpp file, that is added to compile line (e.g. via CMakeLists.txt or any other means)

And eventually main():

Just to discover the following linking error:

As mentioned above, I think all (most?) of us had this at least one time in our C++ programming career.

So what makes C++ Templates so special and makes it impossible for us to place a Template class definition in cpp file, compile it and try to call this function?

Before we answer this question, let’s take a step back and understand the compile/linker stages.

To put it simply, there are few steps to compile your C++ code. There’s a preprocessor step, C++ files to object files compilation step and finally, the linker will create a binary – executable or shared library. Creating a static library is just an archive of all of those object files (compilation units) and no linking step is involved in this case – so let’s ignore it for now (linking happens when exe/so is linked with your static lib).

Here is an example for a simple scenario, using non-Templated code:

And your main() would be something like:

And compiling the above would pass without issue. This is really a simple, vanilla example. Let’s inspect what we have on the file-system:

Note the getVal() that is part of the .text section. We have full definition in our compiled object file.

When main() is linked with this object file, the linker is capable of finding this symbol and all is good. Here is how main() object file looks like:

Note the *UND* kobi::MyNonTemplate::getVal() const – fear not! When creating the entire executable the Linker will find the definition and when you inspect the actual binary:

You see? all good. We have kobi::MyNonTemplate::getVal() const in the .text section and both compilation and linking stages completed w/o errors.

Now, let’s inspect what happened with the Templated one.

Here is the compiled .cpp file that contained that template member function definition:

Unlike the non-templated one, there is nothing interesting here!

getVal() does not exist here in any shape or form. So what happened?

Well, to put it simple, Template, and in this case class Template, is just a vehicle, a special syntax in the language for creating concrete types (or functions), concrete definitions. But for this to happen, one would need to:

  1. Ask the compiler to create, instantiate the class type. (same idea for functions btw).
  2. The compiler must have full visibility to the definition at the time of the instantiation. (unless extern template is used – this part is not covered in this article).

When we compiled the class Template in its own “compilation unit” and tried to instantiate this class type (+ calling a member function) inside main(), the compiler (at the point of instantiation) only had the declaration of the member function since we #include <> the header file. The compiler did not see the complete definition. It’s like there is no such definition!

Wait you say – but I have the cpp compiled. True, but remember, there is no spoon! There is no member getVal() function definition compiled into this translation unit!

It’s just bunch of code that no one instantiate when this specific “template” cpp was compiled!

OK. so what can we do? Few options that I will highlight here.

Define the body of the function in the header itself

There are couple ways you can define the function in the class Template header.

We want to do this so when another cpp includes this header, the point of instantiation has full visibility to the definition.

Or, you can leave the class with just function declarations, and have the definition somewhere outside of the class template:

If you check your compiled object with objdump , you’ll see that getVal() is now showing in your .text section.

Oh yes – using the above method, there is no .cpp anymore. You don’t need it and of course, you don’t need to compile it as a standalone .cpp file.

#include your cpp file in your header

Usually when I introduce this method to a junior C++ programmers, it really confuses them. How can you #include<> a .cpp file in your header. Well, I usually explain them that technically, I can #include<> (almost?) anything, and include it anywhere inside headers of C++ files. Not that every such #include<> would make sense, but yes, I can do it. Sue me!

What does it mean to have #include<> of one file within another file. It means the preprocessor will take the file mentioned in the preprocessor directive as #include<> and will just embed it in the overall buffer that will be fed later into the next compilation step. Don’t believe me? No problem. Run your compile line with -E (of course, no need to use -o option and similar) and you’ll become a true believer 🙂 You’ll see the output buffer of the preprocessor and if you have #include<> directives (and we assume that the preprocessor can find those files), you’ll see the content of these files in the output buffer.

So let’s put this knowledge into practice:

And here is your cpp, it would not have a #include<> of the header:

Again, if you check with objdump, you’ll notice getVal() is in the .text section.

But what if I really want to _compile_ my template cpp file?

I said above that it does not really make sense to compile a .cpp Template file. Well, I lied a bit. This is how you explain things in C++, you lie a bit and then, towards the end, you have a twist in the plot.

In some use cases, you might have the following requirements when working with external entities:

  1. You cannot release the definitions of your class (of function) Template. (IP reasons or you just don’t want others to see how bad is your code 😉
  2. You are OK to allow instantiation of only specific types.

In both cases, the mechanism is as described below:

  1. You write your class definition with only the function member declaration in the header.
  2. You write your class function member definition in a separate .cpp. This .cpp will be compiled.
  3. In the above mentioned .cpp, you instantiate this class Template with specific types. The compiler will generate full class type definition at the point of this explicit instantiation. (btw, this is applicable to non-member functions as well).

Example of such .cpp (#include<> of the header omitted):

I have explicit instantiation of this class type for int and float.

and example of usage:

Note that we cannot instantiate and use getVal() of double since we are back to square one with this type. There is no definition available for double!

Note that since the constructor is implicitly generated (and hence available to the compiler and to the linker) , instance of kobi::MyTemplate<double> would compile and link without issue. I just cannot call functions using this instance.

But there is one drawback with this approach.

One of the beautiful parts of class Template is that you only generate code that you actually use. So if, for example, I have other function(s) in the class Template, and I’m using the traditional way to write Templates (i.e. include the definition in the header and NOT having an explicit instantiate the entire class Template with a specific type), then in this case, objdump will only show me what is actually being used. Example:

If your main() does not invoke print() on some MyTemplate<> instance, this function would not show up in the object file!

However, when you explicitly instantiate this class Template with the syntax showed above:

Then, no matter if you are using or not using parts of the class Template, everything will be compiled and be part of the .text section.

Did anyone order code bloat?

Yes, print() will be there even if I did not use it in main() .

Conclusions

The traditional way to write and use Template code is to have the definition visible to the compiler at the time of instantiation. You can use it by inline-ing the definition in the body of the class, or outside of the class. Another approach is to write a .cpp (or any other extension) file that contains definitions of the member function definitions and #include<> it in the header. In all of the above, you do not compile a separate .cpp Template file.

Another approach is to compile a separate .cpp file and explicitly instantiate the class Template with specific types. These are the only types you could use with this class Template. Also, using this approach the compiler will instantiate the entire class member functions regardless of what you actually use. This is different from the traditional approach where the compiler is generating only parts that you actually use.

Function alias vs Function pointer alias

Last weekend (4/4/2021) I was sitting down and working on my San Diego C++ agenda for the 25th upcoming session.

One of things I really like presenting is few riddles from cppquiz.org

I stumbled upon this one: https://cppquiz.org/quiz/question/227 . Simple and easy one.

Here is the code in question:

And the question is what is the output.

So clearly the question is what does the following syntax mean?

Initially, the “using” part looked like an innocent typedef of a function pointer. But is it?

A quick check with cppinsights.io shows the following

Clearly this is not a function pointer typedef, and we are not defining any “f” as a data member.

Instead, we are actually defining a function named as “f” that returns “int” and takes no params.

So when does it look like a function pointer and when it is not?

Here is a small playground cppinsights.io.

And the gist of it is described in the following snippet: