<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: weiqiang.shan</title>
    <description>The latest articles on DEV Community by weiqiang.shan (@weiqiang).</description>
    <link>https://dev.to/weiqiang</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3426006%2F72f839d1-e1cf-49f3-ad0a-a98a80b420a5.png</url>
      <title>DEV Community: weiqiang.shan</title>
      <link>https://dev.to/weiqiang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/weiqiang"/>
    <language>en</language>
    <item>
      <title>Proof for Floyd’s tortoise and hare</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sun, 17 Aug 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/proof-for-floyds-tortoise-and-hare-2m13</link>
      <guid>https://dev.to/weiqiang/proof-for-floyds-tortoise-and-hare-2m13</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxlepswpdnymwf1iq8cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxlepswpdnymwf1iq8cc.png" alt="alt text" width="800" height="930"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
    </item>
    <item>
      <title>Type systems: Part III Json</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sun, 10 Aug 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/type-systems-part-iii-json-902</link>
      <guid>https://dev.to/weiqiang/type-systems-part-iii-json-902</guid>
      <description>&lt;p&gt;Previously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-systems-part-i-2ge"&gt;Type systems: Part I&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-systems-part-ii-protobuf-reflection-col"&gt;Type systems: Part II Protobuf Reflection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;json itself is a kind of &lt;em&gt;data format&lt;/em&gt;, NOT &lt;em&gt;type format&lt;/em&gt;. To operate on json, we need a &lt;em&gt;type format&lt;/em&gt;, which is the program to operate json data. This program might be a dynamic typing system, like &lt;code&gt;nolmann::json&lt;/code&gt; or static typing system, for example a program that can only parse data that are of specific json format.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;json schema&lt;/em&gt; can be loosely compared with &lt;em&gt;type&lt;/em&gt;, since a &lt;em&gt;json schema&lt;/em&gt; actually defines a &lt;em&gt;class&lt;/em&gt; of json data format, like what the &lt;em&gt;type&lt;/em&gt; does&lt;/li&gt;
&lt;li&gt;Since user directly write &lt;em&gt;json data&lt;/em&gt;, which means that the format is &lt;em&gt;inherently&lt;/em&gt; dynamic, so json inherently needs a dynamic type system to represent &lt;em&gt;json data&lt;/em&gt;. Of course, static type system can also be used, but this requires that the user write the &lt;em&gt;json data&lt;/em&gt; with fixed format, otherwise, the parse will fail.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nlohmann::json&lt;/code&gt; is a &lt;em&gt;dynamic typing&lt;/em&gt; system to represent json. It’s &lt;em&gt;dynamic&lt;/em&gt; in the sense of that it can represent any json, but itself is &lt;em&gt;static&lt;/em&gt;. All programs are &lt;em&gt;static&lt;/em&gt; in the low level, &lt;em&gt;dynamic&lt;/em&gt; only are acheived through static programs. To dynamically support json data format, &lt;code&gt;nlohmann::json&lt;/code&gt; combines underlying &lt;em&gt;type format&lt;/em&gt; and &lt;em&gt;dynamic typing sytem&lt;/em&gt; into one, and also support compile time conversion with user type through C++ meta-programming.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a json file. It’s a &lt;em&gt;data format&lt;/em&gt;, meaning that this is a piece of &lt;em&gt;data&lt;/em&gt;. It is unique and can not have any other &lt;em&gt;instantiation&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "MyMessage": [
        {
            "name": "weiqiang.shan"
        },
        {
            "age": 18
        },
        23,
        "Hello"
    ]
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;em&gt;json schema&lt;/em&gt;. It describes one kind of &lt;em&gt;json data&lt;/em&gt;. This schema can have many json data &lt;em&gt;instantiations&lt;/em&gt;, like above json file. It works like a &lt;em&gt;type&lt;/em&gt;. But it is not actually a &lt;em&gt;type&lt;/em&gt;, since there is no type name. It is just a descriptor of what should a json data look like, what attributes json data should have, etc. It does not define a &lt;em&gt;generalized&lt;/em&gt; type that can be &lt;em&gt;reused&lt;/em&gt; with a type name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "MyMessage": {
      "type": "array",
      "minItems": 4,
      "maxItems": 4,
      "items": [
        {
          "type": "object",
          "properties": {
            "name": {
              "type": "string"
            }
          },
          "required": ["name"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "age": {
              "type": "number"
            }
          },
          "required": ["age"],
          "additionalProperties": false
        },
        {
          "type": "number"
        },
        {
          "type": "string"
        }
      ]
    }
  },
  "required": ["MyMessage"],
  "additionalProperties": false
} 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;em&gt;mirror&lt;/em&gt; protobuf definition for above json schema. It can be used to represent above json data. If we use this protobuf definiton to write a program, we build a &lt;em&gt;static typing system&lt;/em&gt; for above json schema, which can only parse this kind of json data. Unlike json schema, every type has a &lt;em&gt;name&lt;/em&gt;, which can be used to &lt;em&gt;instantiate&lt;/em&gt; type instance and can be &lt;em&gt;reused&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";

package tmp;

// Message representing the root object
message RootMessage {
  repeated MyMessageItem MyMessage = 1;
}

// Union type to represent the mixed array items
message MyMessageItem {
  oneof value {
    NameObject name_value = 1;
    AgeObject age_value = 2;
    int32 number_value = 3;
    string string_value = 4;
  }
}

// Object with name property
message NameObject {
  string name = 1;
}

// Object with age property  
message AgeObject {
  int32 age = 1;
} 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how the &lt;code&gt;nlohmann::json&lt;/code&gt; dynamically represents all json data. At it’s core, it actually is a &lt;em&gt;type erasure&lt;/em&gt; system. All json data, whether it’s numbers, strings, binary, object , list are type erased and be represent using one single type. Type erasure happens during construction, &lt;em&gt;when the binding of constructor and destructor is finished&lt;/em&gt;, through &lt;code&gt;value_t&lt;/code&gt;, which is enum to represent type of json data. Different &lt;code&gt;value_t&lt;/code&gt; will be created and destructed differently. This is the core idea of &lt;em&gt;type erasure&lt;/em&gt;: &lt;strong&gt;hide specific type information in implementation, while in the interface expose unified type representation and complete the binding during construction.&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-erasure-part-i-13p5"&gt;Type Erasure: Part I&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-erasure-part-two-how-stdfunction-works-3e7j"&gt;Type Erasure Part Two: How std::function Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/weiqiang/type-erasure-part-three-the-downside-42bl"&gt;Type Erasure Part Three: The Downside&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    /*!
    @brief a JSON value

    The actual storage for a JSON value of the @ref basic_json class. This
    union combines the different storage types for the JSON value types
    defined in @ref value_t.

    JSON type | value_t type | used type
    --------- | --------------- | ------------------------
    object | object | pointer to @ref object_t
    array | array | pointer to @ref array_t
    string | string | pointer to @ref string_t
    boolean | boolean | @ref boolean_t
    number | number_integer | @ref number_integer_t
    number | number_unsigned | @ref number_unsigned_t
    number | number_float | @ref number_float_t
    binary | binary | pointer to @ref binary_t
    null | null | *no value is stored*

    @note Variable-length types (objects, arrays, and strings) are stored as
    pointers. The size of the union should not exceed 64 bits if the default
    value types are used.

    @since version 1.0.0
    */
    union json_value
    {
        /// object (stored with pointer to save storage)
        object_t* object;
        /// array (stored with pointer to save storage)
        array_t* array;
        /// string (stored with pointer to save storage)
        string_t* string;
        /// binary (stored with pointer to save storage)
        binary_t* binary;
        /// boolean
        boolean_t boolean;
        /// number (integer)
        number_integer_t number_integer;
        /// number (unsigned integer)
        number_unsigned_t number_unsigned;
        /// number (floating-point)
        number_float_t number_float;

        /// default constructor (for null values)
        json_value() = default;
        /// constructor for booleans
        json_value(boolean_t v) noexcept : boolean(v) {}
        /// constructor for numbers (integer)
        json_value(number_integer_t v) noexcept : number_integer(v) {}
        /// constructor for numbers (unsigned)
        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
        /// constructor for numbers (floating-point)
        json_value(number_float_t v) noexcept : number_float(v) {}
        /// constructor for empty values of a given type
        json_value(value_t t)
        {
            switch (t)
            {
                case value_t::object:
                {
                    object = create&amp;lt;object_t&amp;gt;();
                    break;
                }

                case value_t::array:
                {
                    array = create&amp;lt;array_t&amp;gt;();
                    break;
                }

                case value_t::string:
                {
                    string = create&amp;lt;string_t&amp;gt;("");
                    break;
                }

                case value_t::binary:
                {
                    binary = create&amp;lt;binary_t&amp;gt;();
                    break;
                }

                case value_t::boolean:
                {
                    boolean = static_cast&amp;lt;boolean_t&amp;gt;(false);
                    break;
                }

                case value_t::number_integer:
                {
                    number_integer = static_cast&amp;lt;number_integer_t&amp;gt;(0);
                    break;
                }

                case value_t::number_unsigned:
                {
                    number_unsigned = static_cast&amp;lt;number_unsigned_t&amp;gt;(0);
                    break;
                }

                case value_t::number_float:
                {
                    number_float = static_cast&amp;lt;number_float_t&amp;gt;(0.0);
                    break;
                }

                case value_t::null:
                {
                    object = nullptr; // silence warning, see #821
                    break;
                }

                case value_t::discarded:
                default:
                {
                    object = nullptr; // silence warning, see #821
                    if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
                    {
                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
                    }
                    break;
                }
            }
        }

        /// constructor for strings
        json_value(const string_t&amp;amp; value) : string(create&amp;lt;string_t&amp;gt;(value)) {}

        /// constructor for rvalue strings
        json_value(string_t&amp;amp;&amp;amp; value) : string(create&amp;lt;string_t&amp;gt;(std::move(value))) {}

        /// constructor for objects
        json_value(const object_t&amp;amp; value) : object(create&amp;lt;object_t&amp;gt;(value)) {}

        /// constructor for rvalue objects
        json_value(object_t&amp;amp;&amp;amp; value) : object(create&amp;lt;object_t&amp;gt;(std::move(value))) {}

        /// constructor for arrays
        json_value(const array_t&amp;amp; value) : array(create&amp;lt;array_t&amp;gt;(value)) {}

        /// constructor for rvalue arrays
        json_value(array_t&amp;amp;&amp;amp; value) : array(create&amp;lt;array_t&amp;gt;(std::move(value))) {}

        /// constructor for binary arrays
        json_value(const typename binary_t::container_type&amp;amp; value) : binary(create&amp;lt;binary_t&amp;gt;(value)) {}

        /// constructor for rvalue binary arrays
        json_value(typename binary_t::container_type&amp;amp;&amp;amp; value) : binary(create&amp;lt;binary_t&amp;gt;(std::move(value))) {}

        /// constructor for binary arrays (internal type)
        json_value(const binary_t&amp;amp; value) : binary(create&amp;lt;binary_t&amp;gt;(value)) {}

        /// constructor for rvalue binary arrays (internal type)
        json_value(binary_t&amp;amp;&amp;amp; value) : binary(create&amp;lt;binary_t&amp;gt;(std::move(value))) {}

        void destroy(value_t t)
        {
            if (
                (t == value_t::object &amp;amp;&amp;amp; object == nullptr) ||
                (t == value_t::array &amp;amp;&amp;amp; array == nullptr) ||
                (t == value_t::string &amp;amp;&amp;amp; string == nullptr) ||
                (t == value_t::binary &amp;amp;&amp;amp; binary == nullptr)
            )
            {
                //not initialized (e.g. due to exception in the ctor)
                return;
            }
            if (t == value_t::array || t == value_t::object)
            {
                // flatten the current json_value to a heap-allocated stack
                std::vector&amp;lt;basic_json&amp;gt; stack;

                // move the top-level items to stack
                if (t == value_t::array)
                {
                    stack.reserve(array-&amp;gt;size());
                    std::move(array-&amp;gt;begin(), array-&amp;gt;end(), std::back_inserter(stack));
                }
                else
                {
                    stack.reserve(object-&amp;gt;size());
                    for (auto&amp;amp;&amp;amp; it : *object)
                    {
                        stack.push_back(std::move(it.second));
                    }
                }

                while (!stack.empty())
                {
                    // move the last item to local variable to be processed
                    basic_json current_item(std::move(stack.back()));
                    stack.pop_back();

                    // if current_item is array/object, move
                    // its children to the stack to be processed later
                    if (current_item.is_array())
                    {
                        std::move(current_item.m_data.m_value.array-&amp;gt;begin(), current_item.m_data.m_value.array-&amp;gt;end(), std::back_inserter(stack));

                        current_item.m_data.m_value.array-&amp;gt;clear();
                    }
                    else if (current_item.is_object())
                    {
                        for (auto&amp;amp;&amp;amp; it : *current_item.m_data.m_value.object)
                        {
                            stack.push_back(std::move(it.second));
                        }

                        current_item.m_data.m_value.object-&amp;gt;clear();
                    }

                    // it's now safe that current_item get destructed
                    // since it doesn't have any children
                }
            }

            switch (t)
            {
                case value_t::object:
                {
                    AllocatorType&amp;lt;object_t&amp;gt; alloc;
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::destroy(alloc, object);
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::deallocate(alloc, object, 1);
                    break;
                }

                case value_t::array:
                {
                    AllocatorType&amp;lt;array_t&amp;gt; alloc;
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::destroy(alloc, array);
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::deallocate(alloc, array, 1);
                    break;
                }

                case value_t::string:
                {
                    AllocatorType&amp;lt;string_t&amp;gt; alloc;
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::destroy(alloc, string);
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::deallocate(alloc, string, 1);
                    break;
                }

                case value_t::binary:
                {
                    AllocatorType&amp;lt;binary_t&amp;gt; alloc;
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::destroy(alloc, binary);
                    std::allocator_traits&amp;lt;decltype(alloc)&amp;gt;::deallocate(alloc, binary, 1);
                    break;
                }

                case value_t::null:
                case value_t::boolean:
                case value_t::number_integer:
                case value_t::number_unsigned:
                case value_t::number_float:
                case value_t::discarded:
                default:
                {
                    break;
                }
            }
        }
    };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
    </item>
    <item>
      <title>Type systems: Part IV Python</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sun, 10 Aug 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/type-systems-part-iv-python-lbd</link>
      <guid>https://dev.to/weiqiang/type-systems-part-iv-python-lbd</guid>
      <description>&lt;p&gt;Previously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-systems-part-i-2ge"&gt;Type systems: Part I&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-systems-part-ii-protobuf-reflection-col"&gt;Type systems: Part II Protobuf Reflection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-systems-part-iii-json-902"&gt;Type systems: Part III Json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;h1&gt;
  
  
  PyTypeObject
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_PyObject_HEAD_EXTRA&lt;/code&gt; macro: pointers that points to previous PyObject and next PyObject&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ob_refcnt&lt;/code&gt;: reference counter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ob_type&lt;/code&gt;: &lt;em&gt;type&lt;/em&gt; of current PyObject instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;PyTypeObject&lt;/code&gt; is the most important type in Python implementation that enables dynamic typing. Type erasure is achieved through this type. See the &lt;a href="https://docs.python.org/3/c-api/typeobj.html" rel="noopener noreferrer"&gt;C-API for CPython&lt;/a&gt;. The most important thing that this type object contains are &lt;em&gt;function pointers&lt;/em&gt;, which are responsible for various operations on instances of this type: allocation, deallocation, hash, etc. This is exactly where the type erasure happens: &lt;em&gt;binding of function pointers during construction and hide detailed operation inside implementation&lt;/em&gt;. Once the binding is finished, an instance, even it’s Python variable, it’s type is fixed, the functions that used to operate on this instance is fixed, until it’s destruction. Even though this Python variable can be bind to another Python instance, might be a different typed instance, but the underlying PyObject’s type is fixed. Compare this with &lt;code&gt;std::function&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;std::function&lt;/code&gt; variable can be used to bind to different typed callables, underneath &lt;code&gt;std::function&lt;/code&gt; keeps different function pointers that implement these callables.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;std::function&lt;/code&gt; variable can be reassigned to another callable with the same signature, with the previous callable properly deallocated by it’s bound deallocators and with new instance + new set of function pointers kept inside the same &lt;code&gt;std::function&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Python’s dynamic typing works very much like &lt;code&gt;std::function&lt;/code&gt;, using type erasure technique. &lt;strong&gt;A PyTypeObject is itself a PyObject instance at runtime&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When a new object is created, its ob_type is set to the appropriate PyTypeObject( &lt;strong&gt;binding during construction, as in type erasure&lt;/strong&gt; ). For example:&lt;/p&gt;

&lt;p&gt;A list object has ob_type set to &amp;amp;PyList_Type. An integer object has ob_type set to &amp;amp;PyLong_Type. For custom types, you define a PyTypeObject and set the object’s ob_type to point to it.&lt;/p&gt;

&lt;p&gt;ob_type is used for type checking functions like isinstance(obj, cls) and issubclass(cls1, cls2). For instance, PyObject_IsInstance(inst, cls) checks if inst-&amp;gt;ob_type is cls or if cls is in the base classes of inst-&amp;gt;ob_type. This is supported by Python C API: Object Protocol, which lists functions like PyObject_IsInstance and P_IsSubclass, relying on the type hierarchy defined by tp_base and tp_bases in PyTypeObject.&lt;/p&gt;

&lt;p&gt;When an operation is performed on an object, Python uses ob_type to find the appropriate function pointers in the PyTypeObject. For example: Calling len() on a list uses list-&amp;gt;ob_type-&amp;gt;tp_as_sequence-&amp;gt;sq_length.&lt;/p&gt;

&lt;p&gt;While possible, changing ob_type (e.g., via &lt;strong&gt;class&lt;/strong&gt; assignment) is restricted. From Python C API: Type Objects, it’s noted that &lt;strong&gt;class&lt;/strong&gt; assignment is only supported for mutable types or ModuleType subclasses, to prevent crashes or undefined behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Class definion in Python actually will instantiate a PyTypeObject
# instance in C during runtime. It is also a PyObject instance and
# have the same lifetime management with other Python instances.
# When this type is not used anymore, it is deallocated. When defined
# this type belongs to a module, tmp.py, and it is reference by this
# module.
class MyClass:
    class_var = 10

    def __init__ (self, x):
        self.x = x

    def method(self):
        print(f"Original method, class_var={self.class_var}")

# Create an instance using this type. This instance is also
# a PyObject and add one more reference count to MyClass's
# PyTypeObject. The type binding happens here during instance
# construction.
obj = MyClass(5)
obj.method() # Outputs: Original method, class_var=10

# Redefine the class. This creates a new PyTypeObject instance and
# makes the original MyClass's reference count one less count. Since
# Now tmp.py module has a new MyClass type. But the original MyClass
# is still in memory, because the obj instance still refers to it.
class MyClass:
    class_var = 20

    def __init__ (self, x, y):
        self.x = x
        self.y = y

    def method(self):
        print(f"New method, class_var={self.class_var}")

# Check existing instance. obj still use the original MyClass, since
# the binding is not changed.
obj.method() # Outputs: Original method, class_var=10

# Create a new instance. Now the new MyClass is used, since inside
# module tmp.py, the MyClass now is the new PyTypeObject.
new_obj = MyClass(5, 10)
new_obj.method() # Outputs: New method, class_var=20

def m(self, sec):
    print("New individual method")

# We can change the class attributes like any other python instance
# Underneath, a type in Python is just a PyTypeObject in C.
MyClass.method = m
# error
# new_obj.method("dummy")
new_obj.method("dummy")

# This is dangerous!! Since it will reduce reference count of the
# orinal MyClass object(class are also runtime PyObject instances)
# to zero, and it will be freed from memory. This will change the
# type of obj, which determines member function poitners,
# destructor pointers, etc, hence create a inconsistency between
# obj's memory and it's type, since it's memory is created by the
# original MyClass type.
obj. __class__ = MyClass
print(obj.class_var)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Inheritence
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;PyTypeObject&lt;/code&gt; structure contains fields that implement inheritance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "&amp;lt;module&amp;gt;.&amp;lt;name&amp;gt;" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* Methods to implement standard operations */
    destructor tp_dealloc;
    printfunc tp_print;
    getattrfunc tp_getattr;
    setattrfunc tp_setattr;
    PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2) or tp_reserved (Python 3) */
    reprfunc tp_repr;

    /* Method suites for standard classes */
    PyNumberMethods *tp_as_number;
    PySequenceMethods *tp_as_sequence;
    PyMappingMethods *tp_as_mapping;

    /* More standard operations (here for binary compatibility) */
    hashfunc tp_hash;
    ternaryfunc tp_call;
    reprfunc tp_str;
    getattrofunc tp_getattro;
    setattrofunc tp_setattro;

    /* Functions to access object as input/output buffer */
    PyBufferProcs *tp_as_buffer;

    /* Flags to define presence of optional/expanded features */
    unsigned long tp_flags;

    const char *tp_doc; /* Documentation string */

    /* call function for all accessible objects */
    traverseproc tp_traverse;

    /* delete references to contained objects */
    inquiry tp_clear;

    /* rich comparisons */
    richcmpfunc tp_richcompare;

    /* weak reference enabler */
    Py_ssize_t tp_weaklistoffset;

    /* Iterators */
    getiterfunc tp_iter;
    iternextfunc tp_iternext;

    /* Attribute descriptor and subclassing stuff */
    struct PyMethodDef *tp_methods;
    struct PyMemberDef *tp_members;
    struct PyGetSetDef *tp_getset;
    struct _typeobject *tp_base;
    PyObject *tp_dict;
    descrgetfunc tp_descr_get;
    descrsetfunc tp_descr_set;
    Py_ssize_t tp_dictoffset;
    initproc tp_init;
    allocfunc tp_alloc;
    newfunc tp_new;
    freefunc tp_free; /* Low-level free-memory routine */
    inquiry tp_is_gc; /* For PyObject_IS_GC */
    PyObject *tp_bases;
    PyObject *tp_mro; /* method resolution order */
    PyObject *tp_cache;
    PyObject *tp_subclasses;
    PyObject *tp_weaklist;
    destructor tp_del;

    /* Type attribute cache version tag. Added in version 2.6 */
    unsigned int tp_version_tag;

    destructor tp_finalize;

} PyTypeObject;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key fields for inheritance are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tp_base&lt;/code&gt;: Points to the immediate base class(PyTypeObject)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tp_bases&lt;/code&gt;: Tuple of all base classes(PyTypeObject)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tp_mro&lt;/code&gt;: Method Resolution Order tuple&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you define a class in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Child(Parent):
    pass

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Python runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a new PyTypeObject for Child&lt;/li&gt;
&lt;li&gt;Sets Child-&amp;gt;tp_base to point to Parent’s PyTypeObject&lt;/li&gt;
&lt;li&gt;Sets Child-&amp;gt;tp_bases to a tuple containing Parent’s PyTypeObject&lt;/li&gt;
&lt;li&gt;Computes the MRO (Method Resolution Order) and stores it in Child-&amp;gt;tp_mro&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inheritence enable current class &lt;em&gt;inherit&lt;/em&gt; attributes from it’s base classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Class (PyTypeObject)
    tp_base → Parent Class (PyTypeObject)
    tp_bases → (Parent1, Parent2, ...) (PyTypeObject)
    tp_mro → (Class, Parent1, Parent2, ..., object)
    tp_dict → {attribute_name: attribute_value, ...}
    tp_new, tp_init, tp_dealloc → function pointers

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Metaclasses
&lt;/h1&gt;

&lt;p&gt;Metaclasses are also &lt;code&gt;PyTypeObject&lt;/code&gt; instances. When you define a metaclass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Meta(type):
    pass

class MyClass(metaclass=Meta):
    pass

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relationship is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MyClass.ob_type points to Meta’s PyTypeObject&lt;/li&gt;
&lt;li&gt;Meta.ob_type points to type’s PyTypeObject (since Meta inherits from type)&lt;/li&gt;
&lt;li&gt;type.ob_type points to itself (since type is its own metaclass)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;metaclass&lt;/em&gt; are classes that inherits from &lt;em&gt;type&lt;/em&gt;, since &lt;em&gt;type&lt;/em&gt; is a &lt;em&gt;PyObject&lt;/em&gt; that can create &lt;em&gt;PyTypeObject&lt;/em&gt;, which are classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Instance (PyObject)
    ob_type → Class (PyTypeObject)
        ob_type → Metaclass (PyTypeObject)  
            ob_type → type (PyTypeObject)
                ob_type → type (self-referential)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Every PyObject only have one &lt;code&gt;ob_type&lt;/code&gt; pointer, hence can only point to one metaclass&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Meta1(type):
    pass

class Meta2(type):
    pass

# SyntaxError: keyword argument repeated: metaclass
class MyClass(metaclass=Meta1, metaclass=Meta2):
    pass

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;metaclass support inheritence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MetaBase(type):
    def __new__ (cls, name, bases, namespace):
        print(f"MetaBase. __new__ : {name}")
        namespace['base_attr'] = 'from_meta_base'
        return super(). __new__ (cls, name, bases, namespace)

class MetaMiddle(MetaBase):
    def __new__ (cls, name, bases, namespace):
        print(f"MetaMiddle. __new__ : {name}")
        namespace['middle_attr'] = 'from_meta_middle'
        return super(). __new__ (cls, name, bases, namespace)

class MetaTop(MetaMiddle):
    def __new__ (cls, name, bases, namespace):
        print(f"MetaTop. __new__ : {name}")
        namespace['top_attr'] = 'from_meta_top'
        return super(). __new__ (cls, name, bases, namespace)

class MyClass(metaclass=MetaTop):
    pass

# Output:
# MetaBase. __new__ : MyClass
# MetaMiddle. __new__ : MyClass  
# MetaTop. __new__ : MyClass

print(MyClass.base_attr) # 'from_meta_base'
print(MyClass.middle_attr) # 'from_meta_middle'
print(MyClass.top_attr) # 'from_meta_top'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At C level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MyClass.ob_type → MetaTop's PyTypeObject
    ob_type → MetaMiddle's PyTypeObject
        ob_type → MetaBase's PyTypeObject
            ob_type → type's PyTypeObject
                ob_type → type's PyTypeObject (self-referential)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both inheritence and metaclass can add attributes to a class, but they work at totally different level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inheritence only &lt;em&gt;inherit&lt;/em&gt; attributes from it’s parents&lt;/li&gt;
&lt;li&gt;Metaclass directly operate on class’s attributes, during class &lt;em&gt;creation&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Meta(type):
    def __new__ (cls, name, bases, namespace):
        print(f"Metaclass executing during class creation")
        namespace['meta_attr'] = 'added by metaclass'
        return super(). __new__ (cls, name, bases, namespace)

class Base:
    base_attr = 'inherited from base'
    def __init__ (self):
        print("Base class executing during instance creation")

# Metaclass executes NOW (during class definition)
class MyClass(Base, metaclass=Meta):
    pass

# Base class attributes are already available
print(MyClass.meta_attr) # 'added by metaclass'
print(MyClass.base_attr) # 'inherited from base'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Metaclass can directly operate on the &lt;em&gt;raw namespace&lt;/em&gt; of the class type: &lt;code&gt;namespace&lt;/code&gt;. Inheritence only inherit attributes from base classes through &lt;em&gt;inheritence lookup&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Metaclass creates class just like anyother PyTypeObject create instances, internally it’s type erasure and once instances are created, the binding is fixed, attributes are added permanently on this class.&lt;/li&gt;
&lt;li&gt;Inheritence is just pointers to parent classes, they can be changed dynamically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Memory in inheritence
&lt;/h1&gt;

&lt;p&gt;When a class has parents, all parents attributes and the child class attributes are stored in one single dictionary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Parent:
    def __init__ (self):
        self.a = 1

class Child(Parent):
    def __init__ (self):
        super(). __init__ ()
        self.b = 2

c = Child()


&amp;gt;&amp;gt;&amp;gt; c. __dict__
{'a': 1, 'b': 2}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can’t quite do a true C++-style “object slicing” in Python, because Python doesn’t physically store a separate “Parent object” inside a “Child object.”&lt;/p&gt;

&lt;p&gt;In Python:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;c&lt;/code&gt; is the Child instance.&lt;/li&gt;
&lt;li&gt;The “Parent part” isn’t a separate object — it’s just that Child inherits the methods and attributes of Parent.&lt;/li&gt;
&lt;li&gt;When you call a Parent method on c, Python simply follows the Method Resolution Order (MRO) to find that method in Parent, but still passes the same c object as self.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Parent:
    def p_method(self):
        print("Parent method, self is:", self)

class Child(Parent):
    def c_method(self):
        print("Child method, self is:", self)

c = Child()
c.p_method() # Works — no casting needed


Parent method, self is: &amp;lt; __main__.Child object at 0x10100dbe0&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
    </item>
    <item>
      <title>Type Erasure Part Three: The Downside</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Tue, 08 Jul 2025 17:00:00 +0000</pubDate>
      <link>https://dev.to/weiqiang/type-erasure-part-three-the-downside-42bl</link>
      <guid>https://dev.to/weiqiang/type-erasure-part-three-the-downside-42bl</guid>
      <description>&lt;p&gt;I talk about two drawbacks about type erasure: confusing &lt;em&gt;type erasure&lt;/em&gt; with &lt;em&gt;object slicing&lt;/em&gt; and the need for manual memory management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confused with Object slicing
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Object slicing&lt;/em&gt; is a different concept. However, it can be confused with &lt;em&gt;type erasure&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class A {
public:
    virtual void foo() { std::cout &amp;lt;&amp;lt; "A::foo()" &amp;lt;&amp;lt; std::endl; }
    int data_a = 1;
};

class B : public A {
public:
    virtual void foo() override { std::cout &amp;lt;&amp;lt; "B::foo()" &amp;lt;&amp;lt; std::endl; }
    int data_b = 2;
};

std::vector&amp;lt;A&amp;gt; vec;
B b;
vec.push_back(b); // Object slicing occurs here

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above example has a false indication that &lt;code&gt;std::vector&amp;lt;A&amp;gt;&lt;/code&gt; can both store objects of type &lt;code&gt;A&lt;/code&gt; and type &lt;code&gt;B&lt;/code&gt;. That’s not true, since all objects of &lt;code&gt;B&lt;/code&gt; is &lt;em&gt;sliced&lt;/em&gt; to become &lt;code&gt;A&lt;/code&gt;. What if we use &lt;code&gt;std::vector&amp;lt;std::shared_ptr&amp;lt;A&amp;gt;&amp;gt;&lt;/code&gt;? Does this avoid &lt;em&gt;object slicing&lt;/em&gt;? The answer is yes and no, because of the resources leakage problem. The final puzzle is a virtual destructor. Let em summarize all possible scenarios:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stored as&lt;/th&gt;
&lt;th&gt;vdtor&lt;/th&gt;
&lt;th&gt;not vdtor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Objects&lt;/td&gt;
&lt;td&gt;[1]&lt;/td&gt;
&lt;td&gt;[2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pointers&lt;/td&gt;
&lt;td&gt;[3]&lt;/td&gt;
&lt;td&gt;[4]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Before going deeper, we first clarify one important point: the memories that are allocated during object creation, &lt;code&gt;new&lt;/code&gt; operation, will be freed during using &lt;code&gt;delete&lt;/code&gt;, whether it is called manually, or by other means(&lt;code&gt;std::shared_ptr&lt;/code&gt; will call &lt;code&gt;delete&lt;/code&gt; for us). Those memory size are stored in metadata during &lt;code&gt;new&lt;/code&gt;. This means if we using &lt;code&gt;new&lt;/code&gt; to allocate a object &lt;code&gt;A&lt;/code&gt;, then cast it to &lt;code&gt;B&lt;/code&gt;, then &lt;code&gt;delete&lt;/code&gt; &lt;code&gt;B&lt;/code&gt;’s pointer, the &lt;code&gt;delete&lt;/code&gt; will free the size allocated during &lt;code&gt;new&lt;/code&gt;, not caring about &lt;code&gt;B&lt;/code&gt;’s impact, which will have many implications. We here differentiate two types of resources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Memory blocks allocated using &lt;code&gt;new&lt;/code&gt;, we call it &lt;em&gt;memory block&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Other resources managed by the object itself, we call it &lt;em&gt;dynamic resources&lt;/em&gt;, such as heap memories, file descriptors.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ok now let’s discuss one by one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stored as objects and with virtual destructors: object slicing happens. The derived class’s destructor will be called on the sliced object and &lt;code&gt;delete&lt;/code&gt; operator will also operate on the sliced object, both of which are &lt;em&gt;undefined behavior&lt;/em&gt; due to the memory slicing.&lt;/li&gt;
&lt;li&gt;Stored as objects and without virtual destructors: object slicing happens. The base class’s destructor will be called on the sliced object, which is ok. But the dynamic resoruces managed by the derived class will be not released. &lt;code&gt;delete&lt;/code&gt; operator will operate on sliced objects, which is UB.&lt;/li&gt;
&lt;li&gt;Stored as pointers and with virtual destructor: everything is ok. &lt;code&gt;delete&lt;/code&gt; will free memory block and virtual destructor will properly manage dynamic resources.&lt;/li&gt;
&lt;li&gt;Stored as pointers and without virtual destructor: &lt;code&gt;delete&lt;/code&gt; will work fine since there are no object slicing. But the dynamic resources managed by the derived class will not be properly released.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The only way is to store a pointer and use virtual destructor. The virtual destructor is not the same as other virtual functions. It will &lt;em&gt;always&lt;/em&gt; be called during destruction phase, so it must be implemented, even it is a pure virtual function. The virtual property of destructor assures that the derived class’s destructor always be called, hence release the relvent dynamic resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual Memory Management
&lt;/h2&gt;

&lt;p&gt;Due to the fact that type is erased, what if user wants to copy, create, move a type erased object? With type information these can be done easily, but with type erased, we do not know the exct type anymore. So we have to manually create these operations. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

// Example classes to test with
class A {
public:
    void foo() { std::cout &amp;lt;&amp;lt; "A::foo()" &amp;lt;&amp;lt; std::endl; }
};

class B {
public:
    void foo() { std::cout &amp;lt;&amp;lt; "B::foo()" &amp;lt;&amp;lt; std::endl; }
};

class TypeErased {
    struct Concept {
        virtual ~Concept() = default;
        virtual void foo() = 0;
        virtual Concept* clone() const = 0;
    };

    template&amp;lt;typename T&amp;gt;
    struct Model : Concept {
        T data;
        Model(T x) : data(std::move(x)) {}
        void foo() override { data.foo(); }
        Concept* clone() const override { 
            return new Model(data);
        }
    };

    Concept* ptr;

public:
    // Constructor
    template&amp;lt;typename T&amp;gt;
    TypeErased(T x) : ptr(new Model&amp;lt;T&amp;gt;(std::move(x))) {}

    // Destructor
    ~TypeErased() { 
        delete ptr; 
    }

    // Copy Constructor
    TypeErased(const TypeErased&amp;amp; other) : ptr(other.ptr-&amp;gt;clone()) {}

    // Copy Assignment Operator
    TypeErased&amp;amp; operator=(const TypeErased&amp;amp; other) {
        if (this != &amp;amp;other) {
            delete ptr;
            ptr = other.ptr-&amp;gt;clone();
        }
        return *this;
    }

    // Move Constructor
    TypeErased(TypeErased&amp;amp;&amp;amp; other) noexcept : ptr(other.ptr) {
        other.ptr = nullptr;
    }

    // Move Assignment Operator
    TypeErased&amp;amp; operator=(TypeErased&amp;amp;&amp;amp; other) noexcept {
        if (this != &amp;amp;other) {
            delete ptr;
            ptr = other.ptr;
            other.ptr = nullptr;
        }
        return *this;
    }

    // Member function
    void foo() { ptr-&amp;gt;foo(); }
};

int main() {
    std::cout &amp;lt;&amp;lt; "=== Testing all special member functions ===" &amp;lt;&amp;lt; std::endl;

    // Constructor
    TypeErased obj1(A{});
    std::cout &amp;lt;&amp;lt; "obj1: ";
    obj1.foo();

    // Copy Constructor
    TypeErased obj2(obj1);
    std::cout &amp;lt;&amp;lt; "obj2 (copy of obj1): ";
    obj2.foo();

    // Copy Assignment
    TypeErased obj3(B{});
    std::cout &amp;lt;&amp;lt; "obj3: ";
    obj3.foo();

    obj3 = obj1; // Copy assignment
    std::cout &amp;lt;&amp;lt; "obj3 (after copy assignment): ";
    obj3.foo();

    // Move Constructor
    TypeErased obj4(std::move(obj2));
    std::cout &amp;lt;&amp;lt; "obj4 (moved from obj2): ";
    obj4.foo();

    // Move Assignment
    TypeErased obj5(B{});
    std::cout &amp;lt;&amp;lt; "obj5: ";
    obj5.foo();

    obj5 = std::move(obj4); // Move assignment
    std::cout &amp;lt;&amp;lt; "obj5 (after move assignment): ";
    obj5.foo();

    // Test with containers
    std::vector&amp;lt;TypeErased&amp;gt; vec;
    vec.push_back(A{}); // Uses move constructor
    vec.push_back(B{}); // Uses move constructor

    std::cout &amp;lt;&amp;lt; "\nVector elements:" &amp;lt;&amp;lt; std::endl;
    for (auto&amp;amp; item : vec) {
        item.foo();
    }

    return 0;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, both type A and type B provides &lt;code&gt;foo&lt;/code&gt; method, we use the &lt;code&gt;TypeErased&lt;/code&gt; to erase the type information, user does not need to know A or B, or anyother classes that have method &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>c</category>
    </item>
    <item>
      <title>Type Erasure Part Two: How std::function Works</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sun, 29 Jun 2025 02:00:00 +0000</pubDate>
      <link>https://dev.to/weiqiang/type-erasure-part-two-how-stdfunction-works-3e7j</link>
      <guid>https://dev.to/weiqiang/type-erasure-part-two-how-stdfunction-works-3e7j</guid>
      <description>&lt;p&gt;std::function Implementation:&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Inherits &lt;code&gt;_Function_base&lt;/code&gt;&lt;/strong&gt; to get the storage, responsible for data, itself contains &lt;code&gt;_M_invoker&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;_M_functor&lt;/code&gt;&lt;/strong&gt; : A union structure that stores actual callable, might be pointer or heap allocated callable objects. The &lt;code&gt;_M_init_functor&lt;/code&gt; will move &lt;code&gt;__f&lt;/code&gt;, the callable to be stored in &lt;code&gt;_M_functor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;_M_manager&lt;/code&gt;&lt;/strong&gt; : A function pointer in &lt;code&gt;_Function_handler&lt;/code&gt; to create/destroy/… the &lt;code&gt;_M_functor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;_M_invoker&lt;/code&gt;&lt;/strong&gt; : A function pointer in &lt;code&gt;_Function_handler&lt;/code&gt; to call the callable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;amp;_My_handler::_M_invoke&lt;/code&gt;/&lt;code&gt;&amp;amp;_My_handler::_M_manager&lt;/code&gt;&lt;/strong&gt; : Static functions bound with &lt;code&gt;_Functor&lt;/code&gt; type providing clone/destroy operations, which operates on the stored callable object. So the stored callable must be compatible with those static function pointers, which is done during construction.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Points to &lt;code&gt;_Function_handler&lt;/code&gt; type&lt;/strong&gt; that do the type erasure of the passed actual callable type, responsible for code&lt;/p&gt;




&lt;p&gt;After construction, the binding is fixed to a specific &lt;code&gt;_functor&lt;/code&gt;, aka user callable. Even though &lt;code&gt;std::function&lt;/code&gt;’s type is only determined by callable signature, &lt;code&gt;_Function_handler&lt;/code&gt;’s type is also determined by the actual callable type that is passed by user during construction.&lt;/p&gt;




&lt;p&gt;The binding between data and code is done at construction phase at compile time. If we assign a &lt;code&gt;std::function&lt;/code&gt; variable to another instance, the data and code must be both changed at the same time, which is done during run time (using the &lt;code&gt;swap(...)&lt;/code&gt; member function). This data and code binding pattern happens for all methods of implementing type erasure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Virtual classes&lt;/strong&gt; are bound to their vtable during compile time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Statically generated template functions&lt;/strong&gt; (or user written functions implementing type erasure) bind data and code at compile time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This data and code binding during compile time is at the core of how type erasure works, since only after the binding, type can be erased.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s4ew98f7c2m0yk9pemh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s4ew98f7c2m0yk9pemh.png" alt="std::function Implementation" width="800" height="1011"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>c</category>
    </item>
    <item>
      <title>Type systems: Part II Protobuf Reflection</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sat, 14 Jun 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/type-systems-part-ii-protobuf-reflection-col</link>
      <guid>https://dev.to/weiqiang/type-systems-part-ii-protobuf-reflection-col</guid>
      <description>&lt;p&gt;Previously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/weiqiang/type-systems-part-i-2ge"&gt;Type systems: Part I&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GPB Workflow
&lt;/h2&gt;

&lt;p&gt;The main workflow starts from &lt;em&gt;proto&lt;/em&gt; definition files and the static interpreter &lt;em&gt;protoc&lt;/em&gt; compiler will compile them into C++ types, which user will use directly. The process can be illustrated like following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsajog6eycl1zk8zjxnk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsajog6eycl1zk8zjxnk7.png" alt="alt text" width="741" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main design pattern of GPB is static generation plus &lt;a href="https://dev.to/weiqiang/type-erasure-part-i-4h4c-temp-slug-3575477"&gt;type erasure&lt;/a&gt; in C++. All user-defined specific types inherit from the &lt;em&gt;Message&lt;/em&gt; base type. All user-defined type information, like field name, field type, message name, field offsets are statically generated and stored in protoc-generated C++ files. During runtime, before main, those information will be registered into global &lt;em&gt;DescriptorPool&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How reflection work
&lt;/h2&gt;

&lt;p&gt;The message creation is based on type erasure. Member access is based on static offset information and type descriptor information. Dynamic type creation is based on &lt;em&gt;DynamicMessage&lt;/em&gt; type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fog2m9epe3ul1ih9rdn4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fog2m9epe3ul1ih9rdn4v.png" alt="alt text" width="800" height="785"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When user calls &lt;code&gt;MessageFactory::generated_factory()-&amp;gt;GetPrototype(descriptor)-&amp;gt;New()&lt;/code&gt;, GPB returns a &lt;em&gt;Message&lt;/em&gt; type. Underneath this virtual type, there are two possibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The protoc-generated C++ type, which is specific C++ type, and the returned &lt;em&gt;Message&lt;/em&gt; type can be cast to it dynamically.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;DynamicMessage&lt;/em&gt; type, which is constructed at runtime by protobuf library.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Code demo
&lt;/h2&gt;

&lt;p&gt;Here I did a demonstration about protocol buffers advanced usage, the whole code can be found at &lt;a href="https://github.com/shan-weiqiang/lab/tree/main/protobuf_reflection" rel="noopener noreferrer"&gt;protobuf reflection code demo&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "my_message.pb.h" // Generated by protoc
#include &amp;lt;absl/strings/string_view.h&amp;gt;
#include &amp;lt;google/protobuf/compiler/importer.h&amp;gt;
#include &amp;lt;google/protobuf/compiler/parser.h&amp;gt;
#include &amp;lt;google/protobuf/descriptor.pb.h&amp;gt;
#include &amp;lt;google/protobuf/dynamic_message.h&amp;gt;
#include &amp;lt;google/protobuf/text_format.h&amp;gt;
#include &amp;lt;iomanip&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;memory&amp;gt;

using namespace std;

// Custom SourceTree for in-memory .proto files
class MemorySourceTree : public google::protobuf::compiler::SourceTree {
public:
  MemorySourceTree(const std::string &amp;amp;name, const std::string &amp;amp;content)
      : filename_(name), content_(content) {}

  google::protobuf::io::ZeroCopyInputStream *
  Open(absl::string_view filename) override {
    if (filename != filename_)
      return nullptr;
    return new google::protobuf::io::ArrayInputStream(
        content_.data(), static_cast&amp;lt;int&amp;gt;(content_.size()));
  }

private:
  std::string filename_;
  std::string content_;
};

int main() {
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  // ============================================
  // Section 1: Static Message Creation
  // Demonstrates creating a message using the generated C++ class
  // This is the most common and straightforward way to use protobuf
  // ============================================
  test::MyMessage static_msg;
  static_msg.set_id(123);
  static_msg.set_name("Static Message");

  cout &amp;lt;&amp;lt; "\n=== Section 1: Static Message Creation ===\n";
  cout &amp;lt;&amp;lt; "----------------------------------------\n";
  cout &amp;lt;&amp;lt; "Message Content:\n" &amp;lt;&amp;lt; static_msg.DebugString();
  cout &amp;lt;&amp;lt; "Type: " &amp;lt;&amp;lt; static_msg.GetTypeName() &amp;lt;&amp;lt; "\n\n";

  // ============================================
  // Section 2: Dynamic Message Creation
  // Shows how to create a message using the descriptor and reflection APIs
  // This is useful when you don't have the generated C++ class at compile time
  // ============================================
  const google::protobuf::Descriptor *descriptor =
      google::protobuf::DescriptorPool::generated_pool()-&amp;gt;FindMessageTypeByName(
          "test.MyMessage");

  if (!descriptor) {
    cerr &amp;lt;&amp;lt; "Descriptor not found!" &amp;lt;&amp;lt; endl;
    return 1;
  }

  google::protobuf::Message *dynamic_msg =
      google::protobuf::MessageFactory::generated_factory()
          -&amp;gt;GetPrototype(descriptor)
          -&amp;gt;New();

  // ============================================
  // Section 3: Type Identity Verification
  // Proves that static and dynamic messages are of the same type
  // Demonstrates that dynamic messages can be cast to their static counterparts
  // ============================================
  cout &amp;lt;&amp;lt; "\n=== Section 3: Type Identity Verification ===\n";
  cout &amp;lt;&amp;lt; "-------------------------------------------\n";
  cout &amp;lt;&amp;lt; "Are descriptors identical? "
       &amp;lt;&amp;lt; (descriptor == test::MyMessage::descriptor() ? "YES" : "NO") &amp;lt;&amp;lt; "\n";

  test::MyMessage *converted_msg = dynamic_cast&amp;lt;test::MyMessage *&amp;gt;(dynamic_msg);
  cout &amp;lt;&amp;lt; "Dynamic cast successful? " &amp;lt;&amp;lt; (converted_msg ? "YES" : "NO")
       &amp;lt;&amp;lt; "\n\n";

  // ============================================
  // Section 4: Memory Compatibility Test
  // Shows that dynamic messages can be modified and accessed just like static
  // ones Demonstrates the memory layout compatibility between static and
  // dynamic messages
  // ============================================
  cout &amp;lt;&amp;lt; "\n=== Section 4: Memory Compatibility Test ===\n";
  cout &amp;lt;&amp;lt; "------------------------------------------\n";

  // Set the same values in dynamic_msg as in static_msg
  const google::protobuf::Reflection *compat_reflection =
      dynamic_msg-&amp;gt;GetReflection();
  const google::protobuf::Descriptor *compat_desc =
      dynamic_msg-&amp;gt;GetDescriptor();

  const google::protobuf::FieldDescriptor *compat_id_field =
      compat_desc-&amp;gt;FindFieldByName("id");
  const google::protobuf::FieldDescriptor *compat_name_field =
      compat_desc-&amp;gt;FindFieldByName("name");

  compat_reflection-&amp;gt;SetInt32(dynamic_msg, compat_id_field, static_msg.id());
  compat_reflection-&amp;gt;SetString(dynamic_msg, compat_name_field,
                               static_msg.name());

  cout &amp;lt;&amp;lt; "Static message content:\n" &amp;lt;&amp;lt; static_msg.DebugString() &amp;lt;&amp;lt; "\n";
  cout &amp;lt;&amp;lt; "Dynamic message content:\n" &amp;lt;&amp;lt; dynamic_msg-&amp;gt;DebugString() &amp;lt;&amp;lt; "\n";

  // Compare serialized values
  string compat_static_serialized, compat_dynamic_serialized;
  static_msg.SerializeToString(&amp;amp;compat_static_serialized);
  dynamic_msg-&amp;gt;SerializeToString(&amp;amp;compat_dynamic_serialized);

  cout &amp;lt;&amp;lt; "Serialized values identical? "
       &amp;lt;&amp;lt; (compat_static_serialized == compat_dynamic_serialized ? "YES" : "NO")
       &amp;lt;&amp;lt; "\n";
  if (compat_static_serialized != compat_dynamic_serialized) {
    cout &amp;lt;&amp;lt; "Static serialized size: " &amp;lt;&amp;lt; compat_static_serialized.size()
         &amp;lt;&amp;lt; "\n";
    cout &amp;lt;&amp;lt; "Dynamic serialized size: " &amp;lt;&amp;lt; compat_dynamic_serialized.size()
         &amp;lt;&amp;lt; "\n";
  }
  cout &amp;lt;&amp;lt; "\n";

  // ============================================
  // Section 5: Basic Reflection API Usage
  // Demonstrates how to use the reflection API to access message fields
  // Shows the basic operations for getting and setting field values
  // ============================================
  test::MyMessage message;
  const google::protobuf::Reflection *reflection = message.GetReflection();
  const google::protobuf::Descriptor *descriptor_message =
      message.GetDescriptor();
  const google::protobuf::FieldDescriptor *id_field =
      descriptor_message-&amp;gt;FindFieldByName("id");

  int32_t id_value = reflection-&amp;gt;GetInt32(message, id_field);
  reflection-&amp;gt;SetInt32(&amp;amp;message, id_field, 42);
  cout &amp;lt;&amp;lt; "\n=== Section 5: Basic Reflection API Usage ===\n";
  cout &amp;lt;&amp;lt; "-------------------------------------------\n";
  cout &amp;lt;&amp;lt; "Message ID after reflection: " &amp;lt;&amp;lt; message.id() &amp;lt;&amp;lt; "\n\n";

  delete dynamic_msg; // Must manage dynamic allocation
  google::protobuf::ShutdownProtobufLibrary();

  // ============================================
  // Section 6: Dynamic Message Type Creation
  // Shows how to create a new message type programmatically
  // Useful for creating message types at runtime without .proto files
  // ============================================
  cout &amp;lt;&amp;lt; "\n=== Section 6: Dynamic Message Type Creation ===\n";
  cout &amp;lt;&amp;lt; "----------------------------------------------\n";
  google::protobuf::DescriptorPool pool(
      google::protobuf::DescriptorPool::generated_pool());
  google::protobuf::FileDescriptorProto file_proto;
  file_proto.set_name("my_dynamic.proto");
  file_proto.set_package("mypackage");

  google::protobuf::DescriptorProto *message_proto =
      file_proto.add_message_type();
  message_proto-&amp;gt;set_name("MyDynamicMessage");

  google::protobuf::FieldDescriptorProto *field = message_proto-&amp;gt;add_field();
  field-&amp;gt;set_name("my_field");
  field-&amp;gt;set_number(1);
  field-&amp;gt;set_type(google::protobuf::FieldDescriptorProto::TYPE_STRING);

  const google::protobuf::FileDescriptor *file_desc =
      pool.BuildFile(file_proto);
  if (!file_desc) {
    std::cerr &amp;lt;&amp;lt; "Failed to build file descriptor!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  const google::protobuf::Descriptor *message_desc = file_desc-&amp;gt;message_type(0);
  if (!message_desc) {
    std::cerr &amp;lt;&amp;lt; "Failed to get message descriptor!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  google::protobuf::DynamicMessageFactory factory;
  google::protobuf::Message *message_dyn =
      factory.GetPrototype(message_desc)-&amp;gt;New();

  const google::protobuf::Reflection *dyn_reflection =
      message_dyn-&amp;gt;GetReflection();
  const google::protobuf::FieldDescriptor *field_desc =
      message_desc-&amp;gt;FindFieldByName("my_field");

  dyn_reflection-&amp;gt;SetString(message_dyn, field_desc,
                            "Hello from dynamic message!");
  std::string value = dyn_reflection-&amp;gt;GetString(*message_dyn, field_desc);
  std::cout &amp;lt;&amp;lt; "Dynamic message field value: " &amp;lt;&amp;lt; value &amp;lt;&amp;lt; std::endl;

  // Without this, there will be seg fault; this is a because the underlyting
  // derived type is not protoc generated c++ class type anymore, it's
  // DynamicMessage type, the reason is unknown
  google::protobuf::UnknownFieldSet *unknown =
      message_dyn-&amp;gt;GetReflection()-&amp;gt;MutableUnknownFields(message_dyn);
  if (unknown) {
    unknown-&amp;gt;AddVarint(999999, 0);
  }
  std::cout &amp;lt;&amp;lt; message_dyn-&amp;gt;DebugString() &amp;lt;&amp;lt; std::endl;

  // ============================================
  // Section 6.5: Immutability of built descriptors
  // Demonstrates that once a descriptor is built, it cannot be modified
  // ============================================
  cout &amp;lt;&amp;lt; "\n=== Section 6.5: Immutability of built descriptors ===\n";
  cout &amp;lt;&amp;lt; "----------------------------------------------------\n";

  // Try to add another field to message_proto
  google::protobuf::FieldDescriptorProto *field2 = message_proto-&amp;gt;add_field();
  field2-&amp;gt;set_name("another_field");
  field2-&amp;gt;set_number(2);
  field2-&amp;gt;set_type(google::protobuf::FieldDescriptorProto::TYPE_INT32);

  cout &amp;lt;&amp;lt; "Added 'another_field' to FileDescriptorProto in memory.\n";

  // The existing message_desc is immutable and won't see the change.
  const google::protobuf::FieldDescriptor *field_desc2 =
      message_desc-&amp;gt;FindFieldByName("another_field");

  cout &amp;lt;&amp;lt; "Is 'another_field' found in the original descriptor? "
       &amp;lt;&amp;lt; (field_desc2 ? "YES" : "NO") &amp;lt;&amp;lt; "\n";
  cout &amp;lt;&amp;lt; "Original descriptor field count: " &amp;lt;&amp;lt; message_desc-&amp;gt;field_count()
       &amp;lt;&amp;lt; "\n\n";

  // To use the new field, you would have to build a new FileDescriptor.
  // Building with the same name will fail because it's already in the pool.
  const google::protobuf::FileDescriptor *new_file_desc_fail =
      pool.BuildFile(file_proto);
  cout &amp;lt;&amp;lt; "Trying to build with same name again: "
       &amp;lt;&amp;lt; (new_file_desc_fail ? "succeeded (unexpected!)"
                              : "failed as expected")
       &amp;lt;&amp;lt; "\n";

  // We have to change the name to build a new version.
  file_proto.set_name("my_dynamic_v2.proto");
  // We must also change the message name to avoid a symbol collision in the
  // pool.
  message_proto-&amp;gt;set_name("MyDynamicMessageV2");
  const google::protobuf::FileDescriptor *new_file_desc_ok =
      pool.BuildFile(file_proto);
  if (new_file_desc_ok) {
    cout &amp;lt;&amp;lt; "Building with a new file and message name succeeded.\n";
    const google::protobuf::Descriptor *new_message_desc =
        new_file_desc_ok-&amp;gt;FindMessageTypeByName("MyDynamicMessageV2");
    if (new_message_desc) {
      cout &amp;lt;&amp;lt; "Found new message: '" &amp;lt;&amp;lt; new_message_desc-&amp;gt;full_name() &amp;lt;&amp;lt; "'\n";
      cout &amp;lt;&amp;lt; "New descriptor field count: " &amp;lt;&amp;lt; new_message_desc-&amp;gt;field_count()
           &amp;lt;&amp;lt; "\n";
      const google::protobuf::FieldDescriptor *new_field_desc =
          new_message_desc-&amp;gt;FindFieldByName("another_field");
      cout &amp;lt;&amp;lt; "Is 'another_field' found in the new descriptor? "
           &amp;lt;&amp;lt; (new_field_desc ? "YES" : "NO") &amp;lt;&amp;lt; "\n";
    } else {
      cout &amp;lt;&amp;lt; "Failed to find 'MyDynamicMessageV2' in new file "
              "descriptor.\n";
    }
  } else {
    cout &amp;lt;&amp;lt; "Building with a new name failed unexpectedly.\n";
  }

  // ============================================
  // Section 7: Proto File String Parsing
  // Demonstrates how to create message types from a .proto file content string
  // Shows how to use the compiler infrastructure to parse proto definitions
  // ============================================
  cout &amp;lt;&amp;lt; "\n=== Section 7: Proto File String Parsing ===\n";
  cout &amp;lt;&amp;lt; "------------------------------------------\n";
  std::string proto_content = R"(
        syntax = "proto3";
        package dynamic;

        message DynamicPerson {
            string name = 1;
            int32 age = 2;
            repeated string hobbies = 3;
            bool is_active = 4;
        }
    )";

  google::protobuf::DescriptorPool descriptor_pool(
      google::protobuf::DescriptorPool::generated_pool());
  MemorySourceTree source_tree("person.proto", proto_content);
  google::protobuf::compiler::SourceTreeDescriptorDatabase source_tree_db(
      &amp;amp;source_tree);

  google::protobuf::FileDescriptorProto file_desc_proto;
  if (!source_tree_db.FindFileByName("person.proto", &amp;amp;file_desc_proto)) {
    std::cerr &amp;lt;&amp;lt; "Failed to parse proto content!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  const google::protobuf::FileDescriptor *file_desc_dyn =
      descriptor_pool.BuildFile(file_desc_proto);
  if (!file_desc_dyn) {
    std::cerr &amp;lt;&amp;lt; "Failed to build file descriptor!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  const google::protobuf::Descriptor *descriptor_dyn =
      file_desc_dyn-&amp;gt;FindMessageTypeByName("DynamicPerson");
  if (!descriptor_dyn) {
    std::cerr &amp;lt;&amp;lt; "Failed to find message descriptor!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  google::protobuf::DynamicMessageFactory factory_dyn(&amp;amp;descriptor_pool);
  const google::protobuf::Message *prototype =
      factory_dyn.GetPrototype(descriptor_dyn);
  if (!prototype) {
    std::cerr &amp;lt;&amp;lt; "Failed to get message prototype!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  std::unique_ptr&amp;lt;google::protobuf::Message&amp;gt; message_dyn_(prototype-&amp;gt;New());
  if (!message_dyn_) {
    std::cerr &amp;lt;&amp;lt; "Failed to create dynamic message!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  // Without this, there will be seg fault
  google::protobuf::UnknownFieldSet *unknown_fields =
      message_dyn_-&amp;gt;GetReflection()-&amp;gt;MutableUnknownFields(message_dyn_.get());
  if (unknown_fields) {
    unknown_fields-&amp;gt;AddVarint(999999, 0);
  }

  const google::protobuf::Reflection *reflection_dyn =
      message_dyn_-&amp;gt;GetReflection();
  if (!reflection_dyn) {
    std::cerr &amp;lt;&amp;lt; "Failed to get reflection interface!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  const google::protobuf::FieldDescriptor *name_field =
      descriptor_dyn-&amp;gt;FindFieldByName("name");
  const google::protobuf::FieldDescriptor *age_field =
      descriptor_dyn-&amp;gt;FindFieldByName("age");
  const google::protobuf::FieldDescriptor *hobbies_field =
      descriptor_dyn-&amp;gt;FindFieldByName("hobbies");
  const google::protobuf::FieldDescriptor *is_active_field =
      descriptor_dyn-&amp;gt;FindFieldByName("is_active");

  if (!name_field || !age_field || !hobbies_field || !is_active_field) {
    std::cerr &amp;lt;&amp;lt; "Failed to find required fields!" &amp;lt;&amp;lt; std::endl;
    return 1;
  }

  reflection_dyn-&amp;gt;SetString(message_dyn_.get(), name_field, "John Doe");
  reflection_dyn-&amp;gt;SetInt32(message_dyn_.get(), age_field, 30);
  reflection_dyn-&amp;gt;SetBool(message_dyn_.get(), is_active_field, true);
  reflection_dyn-&amp;gt;AddString(message_dyn_.get(), hobbies_field, "Reading");
  reflection_dyn-&amp;gt;AddString(message_dyn_.get(), hobbies_field, "Hiking");
  reflection_dyn-&amp;gt;AddString(message_dyn_.get(), hobbies_field, "Programming");

  std::cout &amp;lt;&amp;lt; "\nDebug Information:\n";
  std::cout &amp;lt;&amp;lt; "Message Type: " &amp;lt;&amp;lt; message_dyn_-&amp;gt;GetTypeName() &amp;lt;&amp;lt; "\n";
  std::cout &amp;lt;&amp;lt; "Descriptor Name: " &amp;lt;&amp;lt; descriptor_dyn-&amp;gt;full_name() &amp;lt;&amp;lt; "\n";
  std::cout &amp;lt;&amp;lt; "Number of Fields: " &amp;lt;&amp;lt; descriptor_dyn-&amp;gt;field_count() &amp;lt;&amp;lt; "\n";
  std::cout &amp;lt;&amp;lt; "Unknown Fields Size: "
            &amp;lt;&amp;lt; message_dyn_-&amp;gt;GetReflection()
                   -&amp;gt;GetUnknownFields(*message_dyn_)
                   .field_count()
            &amp;lt;&amp;lt; "\n";

  std::cout &amp;lt;&amp;lt; "\nTrying DebugString():\n";
  std::cout &amp;lt;&amp;lt; message_dyn_-&amp;gt;DebugString() &amp;lt;&amp;lt; "\n\n";

  // ============================================
  // Section 8: Static vs Dynamic Message Comparison
  // Creates a static DynamicPerson message and compares its serialization
  // with the dynamic message to verify they are identical
  // ============================================
  cout &amp;lt;&amp;lt; "\n=== Section 8: Static vs Dynamic Message Comparison ===\n";
  cout &amp;lt;&amp;lt; "------------------------------------------\n";
  test::DynamicPerson static_person;
  static_person.set_name("John Doe");
  static_person.set_age(30);
  static_person.set_is_active(true);
  static_person.add_hobbies("Reading");
  static_person.add_hobbies("Hiking");
  static_person.add_hobbies("Programming");

  // Clear unknown fields before serialization for fair comparison
  message_dyn_-&amp;gt;GetReflection()
      -&amp;gt;MutableUnknownFields(message_dyn_.get())
      -&amp;gt;Clear();

  std::string static_serialized, dynamic_serialized;
  static_person.SerializeToString(&amp;amp;static_serialized);
  message_dyn_-&amp;gt;SerializeToString(&amp;amp;dynamic_serialized);

  std::cout &amp;lt;&amp;lt; "Static vs Dynamic Message Comparison:\n";
  std::cout &amp;lt;&amp;lt; "Serialized data identical? "
            &amp;lt;&amp;lt; (static_serialized == dynamic_serialized ? "YES" : "NO") &amp;lt;&amp;lt; "\n";

  if (static_serialized != dynamic_serialized) {
    std::cout &amp;lt;&amp;lt; "Static serialized size: " &amp;lt;&amp;lt; static_serialized.size() &amp;lt;&amp;lt; "\n";
    std::cout &amp;lt;&amp;lt; "Dynamic serialized size: " &amp;lt;&amp;lt; dynamic_serialized.size()
              &amp;lt;&amp;lt; "\n";

    // Print hex representation of both serialized messages for debugging
    std::cout &amp;lt;&amp;lt; "Static serialized (hex): ";
    for (unsigned char c : static_serialized) {
      printf("%02x ", c);
    }
    std::cout &amp;lt;&amp;lt; "\nDynamic serialized (hex): ";
    for (unsigned char c : dynamic_serialized) {
      printf("%02x ", c);
    }
    cout &amp;lt;&amp;lt; "\n";
  }

  return 0;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GPB is static typing
&lt;/h2&gt;

&lt;p&gt;GPB support dynamic type creation, dynamic data creation, but it relies on pre-defined &lt;em&gt;schema&lt;/em&gt; and once the type is built, it is immutable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Runtime type creation is just defered compile time type registration. When user use protoc to generate types and those types are registered during program start up, before main. The registration process is the same as the so-called runtime type creation, both reading from a text and compose a type descriptor, then register it to &lt;em&gt;DescriptorPool&lt;/em&gt;. More importantly, once the type has been registered, it can not be modified: GPB can not update all instance of this type if the type itself can be modified during runtime. Think about what happens if one type is changed, might be a new field is added, and the existing instancees can not be updated to contain this new field in data.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;DynamicMessage&lt;/em&gt; type do bring GPB one step close to true dynamic type. It works very much like &lt;em&gt;PyObject&lt;/em&gt; class in Python. However, it still depend on &lt;em&gt;Descriptor&lt;/em&gt; to contruct one message, yet again &lt;em&gt;Descriptor&lt;/em&gt; can not be changed once registered, it’s &lt;em&gt;immutable&lt;/em&gt;. In Python, class attributes and instance attributes are added into a dynamic expanding list, which can be added and deleted at runtime. This can not be done with GPB’s descriptor. For GPB to be truely dynamic, it must make &lt;em&gt;Descriptor&lt;/em&gt; type dynamic at runtime, since the descriptors are the real ones that defines a &lt;em&gt;type&lt;/em&gt;. But in GPB, &lt;em&gt;Descriptor&lt;/em&gt; can be created and changed during runtime, but it can not be changed once registered.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GPB supports ​​runtime descriptor construction​​ and ​​dynamic message handling​​ (via DynamicMessage), but the ​​immutability of registered descriptors​​ and the ​​inability to propagate type changes to existing instances​​ make it a ​​static type system​​ with limited runtime flexibility—not a true dynamic typing system. This design prioritizes performance, safety, and serialization reliability over full runtime dynamism. GPB only dynamically create a &lt;em&gt;object&lt;/em&gt; according to a &lt;em&gt;descriptor&lt;/em&gt;. It’s like building a house according to a drawing. With reflection and DynamicMessage, Protobuf does have limited dynamic typing feature, such as creating type and instance at runtime, but the immutable feature of it’s type limit it’s power.&lt;/p&gt;

&lt;p&gt;Python achieves the propagation of ​​type changes to existing instances​​ through its dynamic object model, leveraging two key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mutable class dictionaries&lt;/li&gt;
&lt;li&gt;Attribute lookup delegation​​&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Python, an instance (obj) stores only its ​​unique instance-level attributes​​ in its own &lt;strong&gt;dict&lt;/strong&gt; (dictionary).For ​​class-level attributes​​ (including methods), the instance delegates to its class. The class holds these attributes in its &lt;strong&gt;dict&lt;/strong&gt;. If you modify a class’s &lt;strong&gt;dict&lt;/strong&gt; (e.g., add/change attributes), all existing instances immediately reflect the changes because attribute lookup always queries the class dynamically. When you access obj.attr: Python checks obj. &lt;strong&gt;dict&lt;/strong&gt; for an instance attribute attr. If not found, it delegates to the ​​class’s &lt;strong&gt;dict&lt;/strong&gt; ​​. If the class doesn’t have it, it checks base classes (MRO). ​​Class-level changes are ​​visible instantly​​ because the lookup happens at runtime, not at instance creation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyClass:
    pass

def new_method(self):
    print(self.x * 2)

obj1 = MyClass()
MyClass.double_x = new_method
obj1.x = 5
obj2 = MyClass()

# obj1 can find double_x and x, can success
obj1.double_x()
# obj2 can find double_x, but not x, fail
obj2.double_x()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For dynamic types, the programmer are programming towards &lt;em&gt;interpreter&lt;/em&gt;. For static types, the programmer are programming towards &lt;em&gt;compiler&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>Compile-Time vs. Run-Time</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Thu, 12 Jun 2025 11:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/compile-time-vs-run-time-2chn</link>
      <guid>https://dev.to/weiqiang/compile-time-vs-run-time-2chn</guid>
      <description>&lt;p&gt;&lt;em&gt;This blog post was co-authored with AI assistance.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Compile-Time vs. Run-Time
&lt;/h1&gt;

&lt;p&gt;Picture compile-time as the resume screener for a job, checking your credentials before you’re hired, and run-time as your actual performance on the job, where real-world challenges test your mettle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile-Time: The Resume Screener
&lt;/h2&gt;

&lt;p&gt;Compile-time is all about &lt;strong&gt;static inspection&lt;/strong&gt; —it’s the phase where the compiler plays bouncer, making sure your code meets the “hard requirements” before it’s allowed to execute. Think of it as a recruiter scanning your resume: Does your syntax check out? Are your types aligned? Are you following the rules?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt; : The compiler catches mismatches early. For example, in C# or Java:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;string my_value = Console.ReadLine();
int i = my_value; // Compiler: "Nope, string can’t be an int!"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents runtime chaos by enforcing type rules upfront.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Syntax Rules&lt;/strong&gt; : Miss a semicolon in C++ or mismatch function parameters? The compiler flags it immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope and Visibility&lt;/strong&gt; : Try accessing an undeclared variable or a private member, and you’ll get a stern “access denied” before the code even runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s like fixing a typo on your resume before the interview—preventive and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run-Time: The Real-World Test
&lt;/h2&gt;

&lt;p&gt;Once your code passes the compile-time “resume check,” it’s time for &lt;strong&gt;run-time&lt;/strong&gt; —the dynamic phase where your program faces the unpredictable. This is your job performance after being hired: the resume got you in, but now you’re dealing with real tasks, unexpected inputs, and shifting conditions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Type Conversion&lt;/strong&gt; : Syntax might be fine, but the data? That’s another story:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int i = int.Parse(my_value); // If my_value is "abc", hello FormatException!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler approves, but run-time decides if the conversion works.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Polymorphism&lt;/strong&gt; : In languages like C++:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Base* b = new Derived();
b-&amp;gt;func(); // Run-time picks Derived::func() via the vtable

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This flexibility—deciding behavior on the fly—is pure run-time magic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource Checks&lt;/strong&gt; : Java and C# watch array bounds (throwing exceptions if you overstep), while C leaves you to fend for yourself:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int arr[5];
int x = arr[10]; // Undefined behavior—good luck!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run-time is your safety net when the real world throws curveballs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qualification Meets Execution
&lt;/h2&gt;

&lt;p&gt;Compile-time and run-time aren’t rivals—they’re a progressive duo. Compile-time ensures your code is &lt;strong&gt;qualified to execute&lt;/strong&gt; (“You meet the minimum standards”), while run-time checks if it &lt;strong&gt;executes successfully&lt;/strong&gt; (“Can you handle the real thing?”).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture: A Staged Defense
&lt;/h2&gt;

&lt;p&gt;In the end, compile-time and run-time are like &lt;strong&gt;design-time protection&lt;/strong&gt; and &lt;strong&gt;operation-time monitoring&lt;/strong&gt; in safety engineering. Compile-time is your preventive review, weeding out structural flaws. Run-time is your dynamic insurance, adapting to chaos and keeping things afloat.&lt;/p&gt;

&lt;p&gt;Next time your compiler yells or your program crashes, think of it as this layered system at work: compile-time says, “You &lt;em&gt;can&lt;/em&gt; do this,” and run-time proves, “You &lt;em&gt;did&lt;/em&gt; it.” It’s this balance that drives modern programming languages, blending performance, safety, and flexibility into the tools we love.&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>Static Storage and Nifty Counter</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Fri, 23 May 2025 13:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/static-storage-and-nifty-counter-993</link>
      <guid>https://dev.to/weiqiang/static-storage-and-nifty-counter-993</guid>
      <description>&lt;p&gt;This is reading notes for &lt;a href="https://en.cppreference.com/w/cpp/language/siof" rel="noopener noreferrer"&gt;&lt;em&gt;static initialization order fiasco&lt;/em&gt;&lt;/a&gt; problem and its solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.cppreference.com/w/cpp/language/storage_duration" rel="noopener noreferrer"&gt;&lt;em&gt;static storage duration&lt;/em&gt;&lt;/a&gt; includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Global variables: &lt;em&gt;external linkage&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;static&lt;/em&gt; members of a class: &lt;em&gt;external linkage&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;static&lt;/em&gt; variables: &lt;em&gt;internal linkage&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;static&lt;/em&gt; local variables inside functions: &lt;em&gt;no linkage&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the &lt;em&gt;static initialization order fiasco&lt;/em&gt; only happens between &lt;em&gt;static objects&lt;/em&gt; which have &lt;em&gt;external linkage&lt;/em&gt;, we only consider global variables and static members of a class. I call them &lt;em&gt;static objects&lt;/em&gt; in the following content.&lt;/p&gt;

&lt;h1&gt;
  
  
  Initialization and destruction order of static objects
&lt;/h1&gt;

&lt;p&gt;Simply put:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inside one translation unit (TU), static objects are initialized in the order of their appearance and deinitialized in reverse order.&lt;/li&gt;
&lt;li&gt;Across TUs, the order is unspecified.&lt;/li&gt;
&lt;li&gt;Initialization order: 

&lt;ul&gt;
&lt;li&gt;Global variables and &lt;em&gt;static&lt;/em&gt; class members: Initialization happens before &lt;code&gt;main&lt;/code&gt;; Deinitialization happens after &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;static&lt;/em&gt; local variables: initialization at first use and deinitialization after &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;static&lt;/em&gt; variables inside TU: Initialization happens before &lt;code&gt;main&lt;/code&gt;; Deinitialization happens after &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;static initialization order fiasco&lt;/em&gt; happens when &lt;em&gt;static objects&lt;/em&gt; across TUs depend on each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// file1.h
class A {
public:
    void doSomething() { /* ... */ }
};
extern A aObj;

// file1.cpp
A aObj;

// file2.h
class B {
public:
    B() { aObj.doSomething(); } // Potential problem: aObj might not be initialized yet
    static B bObj;
};

// file2.cpp
#include "file1.h" 
#include "file2.h"
B B::bObj;

int main() {
  return 0;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Construct On First Use Idiom
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use" rel="noopener noreferrer"&gt;&lt;em&gt;Construction On First Use Idiom&lt;/em&gt;&lt;/a&gt; uses &lt;em&gt;static&lt;/em&gt; local variable inside function to avoid the problem. Since &lt;em&gt;static&lt;/em&gt; local variable inside a function has &lt;em&gt;no linkage&lt;/em&gt; and is initialized when first used, this will prevent the order problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fred&amp;amp; x()
{
  static Fred* ans = new Fred();
  return *ans;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ans&lt;/code&gt; will &lt;em&gt;never&lt;/em&gt; be destructed, which avoids the problem of destruction order. The memory will be freed when the process terminates by the operating system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fred&amp;amp; x()
{
  static Fred ans; // was static Fred* ans = new Fred();
  return ans; // was return *ans;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If some &lt;em&gt;static object&lt;/em&gt; that depends on &lt;code&gt;ans&lt;/code&gt; is destructed after &lt;code&gt;ans&lt;/code&gt; is destructed, there will be the same problem as &lt;em&gt;static initialization order fiasco&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Nifty Counter Idiom
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter" rel="noopener noreferrer"&gt;&lt;em&gt;Nifty Counter Idiom&lt;/em&gt;&lt;/a&gt; can solve both initialization and deinitialization order problems. Here I quote the full explanation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Stream.h
#ifndef STREAM_H
#define STREAM_H

struct Stream {
  Stream ();
  ~Stream ();
};
extern Stream&amp;amp; stream; // global stream object

static struct StreamInitializer {
  StreamInitializer ();
  ~StreamInitializer ();
} streamInitializer; // static initializer for every translation unit

#endif // STREAM_H


// Stream.cpp
#include "Stream.h"

#include &amp;lt;new&amp;gt; // placement new
#include &amp;lt;type_traits&amp;gt; // aligned_storage

static int nifty_counter; // zero initialized at load time
static typename std::aligned_storage&amp;lt;sizeof (Stream), alignof (Stream)&amp;gt;::type
  stream_buf; // memory for the stream object
Stream&amp;amp; stream = reinterpret_cast&amp;lt;Stream&amp;amp;&amp;gt; (stream_buf);

Stream::Stream ()
{
  // initialize things
}
Stream::~Stream ()
{
  // clean-up
} 

StreamInitializer::StreamInitializer ()
{
  if (nifty_counter++ == 0) new (&amp;amp;stream) Stream (); // placement new
}
StreamInitializer::~StreamInitializer ()
{
  if (--nifty_counter == 0) stream.~Stream ();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The header file of the Stream class must be included before any member function can be called on the Stream object. An instance of the StreamInitializer class is included in each compilation unit. Any use of the Stream object follows the inclusion of the header, which ensures that the constructor of the initializer object is called before the Stream object is used.&lt;/p&gt;

&lt;p&gt;The Stream class’ header file declares a reference to the Stream object. In addition this reference is extern, meaning it is defined in one translation unit and accesses to it are resolved by the linker rather than the compiler. The implementation file for the Stream class finally defines the Stream object, but in an unusual way: it first defines a static (i.e. local to the translation unit) buffer. This buffer is both properly aligned and big enough to store an object of type Stream. The reference to the Stream object defined in the header is then set to point to this buffer. This buffer workaround enables fine-grained control of when the Stream object’s constructor and destructor are called. In the example above, the constructor is called within the constructor of the first StreamInitializer object, using placement new to place it within the buffer. The Stream object’s destructor is called when the last StreamInitializer object is destroyed.&lt;/p&gt;

&lt;p&gt;This workaround is necessary because defining a Stream variable within Stream.cpp - be it static or not - would define it after the StreamInitializer, which is defined by including the header. Then, the StreamInitializer’s constructor would run before theStream’s constructor, and even worse, the initializer’s destructor would run after the Stream object’s destructor. The buffer solution above avoids this.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>middleware</category>
    </item>
    <item>
      <title>Type Erasure: Part I</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sun, 20 Apr 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/type-erasure-part-i-13p5</link>
      <guid>https://dev.to/weiqiang/type-erasure-part-i-13p5</guid>
      <description>&lt;p&gt;This is understanding notes for this presentation: &lt;a href="https://www.youtube.com/watch?v=p-qaf6OS_f4" rel="noopener noreferrer"&gt;C++ Type Erasure Demystified - Fedor G Pikus - C++Now 2024&lt;/a&gt;. Ppt at &lt;a href="https://github.com/shan-weiqiang/shan-weiqiang.github.io/blob/main/assets/files/Cpp_Type_Erasure_Demystified.pdf" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core logic behind type erasure&lt;/li&gt;
&lt;li&gt;Implementation methods for type erasure&lt;/li&gt;
&lt;li&gt;Abstraction of type&lt;/li&gt;
&lt;li&gt;Type erasure of std::function&lt;/li&gt;
&lt;li&gt;Type erasure of std::shared_ptr deleter&lt;/li&gt;
&lt;li&gt;More about binding&lt;/li&gt;
&lt;li&gt;std::variant&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core logic behind type erasure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulate type infomation in implementation, remove type information in interface&lt;/li&gt;
&lt;li&gt;Different implementation for different types might be manually coded or generated by compiler(C++) 

&lt;ul&gt;
&lt;li&gt;Template instantiation&lt;/li&gt;
&lt;li&gt;Virtual inheritence&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Dispatch of implementation happens at construction phase. It might happens at compile time or runtime: 

&lt;ul&gt;
&lt;li&gt;For template instantiated implementations, it happens at compile time&lt;/li&gt;
&lt;li&gt;For virtual inheritence, it happens at runtime &lt;strong&gt;Dispatch is all about redirection of function pointers&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The user of the interface is not aware of the passed type information, hence the type is &lt;em&gt;erased&lt;/em&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;What’s the benifit of type erasure? Even though there is a type erased interface, like &lt;code&gt;qsort&lt;/code&gt;, but when the &lt;code&gt;qsort&lt;/code&gt; is actually used, we still need to pass &lt;em&gt;correct implementation&lt;/em&gt; of the comparision function to &lt;code&gt;qsort&lt;/code&gt;, we just &lt;strong&gt;defer&lt;/strong&gt; the choice of implementation to later time. The &lt;code&gt;qsort&lt;/code&gt; function acts as a &lt;em&gt;variation point&lt;/em&gt;, it &lt;strong&gt;abstract&lt;/strong&gt; the sorting logic functionality by using only the type erased compare function. When &lt;code&gt;qsort&lt;/code&gt; is called, it binds the sorting logic to the actual type compare implementation. Without &lt;code&gt;qsort&lt;/code&gt; that use the type-erased compare interface to implement &lt;em&gt;common behavior&lt;/em&gt; of sorting, the type-erased compare interface will have no practical meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;qsort&lt;/code&gt; algorithm stands for the &lt;em&gt;common behavior&lt;/em&gt;, which utilize the type-erased interface&lt;/li&gt;
&lt;li&gt;The implementation of this &lt;em&gt;common behavior&lt;/em&gt; abstract out any specific type information&lt;/li&gt;
&lt;li&gt;When the implementation of this &lt;em&gt;common behavior&lt;/em&gt; is used, user decides which type it is actually operates on(the &lt;em&gt;common behavior&lt;/em&gt; implementation still know nothing about type whatsoever)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this &lt;em&gt;abstraction&lt;/em&gt;, we have to implement &lt;code&gt;qsort&lt;/code&gt; for each individual type and the sorting algorithm has to be coded every time for each type. Now with type erasure, we only need to code the actual sorting algorithm &lt;em&gt;once&lt;/em&gt; for all possible types. Of cource the compare function has to be implemented for each type, since each type has their own comparing logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation methods for type erasure
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Virtual inheritance: redirection hanppens when using base class pointer to call implementation in derived class(whose type is erased)&lt;/li&gt;
&lt;li&gt;Static templated functions: C++ compiler will generate code implementation for each template instantiation. It’s the same as C, but code generated instead of manually written. Note that generated static functions are class members, which means that the amount of instantiations equals the number of generated class member functions.&lt;/li&gt;
&lt;li&gt;Vtable: similar as 2, this time use a vtable to point to generated static class member functions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note: &lt;strong&gt;Method 3 is how &lt;code&gt;std::function&lt;/code&gt; is implemented&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;cstdlib&amp;gt;

// Following code are in *.cpp file, without Some exposed
// But user will call this code through type erased interface: void
// print_data(const void *p). This is the core of type erasure: encapsulate type
// infomation in implementation, remove type information in interface.
struct Some {
  int data;
};
bool less(const void *l, const void *r) {
  return static_cast&amp;lt;const Some *&amp;gt;(l)-&amp;gt;data &amp;lt;
         static_cast&amp;lt;const Some *&amp;gt;(r)-&amp;gt;data;
}

// The declaration in *.h, exposed to external user
// ! Here is where the type erasure happens
bool less(const void *, const void *);

// User of type erasure: qsort does not need to know which type it will sort,
// type is erased from qsort: type erasure is an abstraction for multiple
// implementations that provide the same behavior, the relevent behavior is what
// matters, not the type. In this example, `compare` parameter requires that two
// elements can be compared, qsort does not care about how it is compared, as
// long as it return a bool value. This gives chances to implement the compare
// logic in source code, instead of in interface code.

// Since type erasure is about abstraction of behavior, it alwarys involve
// redirection of function pointers, no matter which way it is implemented. This
// redirection of function pointer is called dispatch, which is another core
// brick in implementing type erasure. Dispatch might happen both at compile
// time or runtime.

// Compared with C, C++ ONLY add implementation methods for type erasure. In C,
// we have to manually write different implementations, like the `less` and
// `more` function in below. In C++, we have the compiler to generate different
// implementation code for us. They all involves template and are done at
// construction phase. The three ways are:
// 1. virtual inheritance: redirection hanppens when using base class pointer to
// call implementation in derived class(whose type is erased)
// 2. static templated functions: C++ compiler will generate
// code implementation for each template instantiation. It's the same as C, but
// code generated instead of manually written. Note that generated static
// functions are class members, which means that the amount of instantiations
// equals the number of generated class member functions.
// 3. vtable: Similar as 2, this time use a vtable to point to instead of
// generating static class member functions.

// One more important fact is that all the C++ ways are of value semantics. The
// implementation is stored as value(function pointers can be seen as value of
// function variables).

// Now we can summarize type erasure as follow:

// Core logic of type erasure:
// 1. Encapsulate type infomation in implementation, remove type information in
// interface.
// 2. The interface provide same behavior, regardless of specific type

// Implementation steps of type erasure involve two distinct phase: how
// implementation code is generated at compile time and how those implementation
// is dispatched to at runtime:

// 1. Statically write type erased code implementation, either manually, or by
// compiler(C++). The type must be inside cpp, not in header(interface)
// 2. Dynamically dispatch function call to the right implementation at runtime.
// How the dispatch is done varies. It can simply be hard coded(like in C qsort
// example in following code). Or it can be done using virtual inheritance in
// C++. Either way, the dispatch, or redirection is determined during
// construction phase. As soon as the construction is complete, the dispatch
// manner is determined.

void qsort(void *base, size_t nmeb, size_t size,
           bool (*compare)(const void *, const void *));

// Following give another type that also use qsort
struct Tome {
  int data;
};
bool more(const void *l, const void *r) {
  return static_cast&amp;lt;const Tome *&amp;gt;(l)-&amp;gt;data &amp;lt;
         static_cast&amp;lt;const Tome *&amp;gt;(r)-&amp;gt;data;
}
bool more(const void *, const void *);

int main() {
  Some a[10];
  Tome b[10];
  // qsort is universal, thanks to the redirection of `compare` parameter
  qsort(a, 10, 4, less);
  qsort(b, 10, 4, more);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Abstraction of type
&lt;/h2&gt;

&lt;p&gt;Type erasure, C++ template, C++ concept, virtual inheritence, what is the common characteristic among them? &lt;strong&gt;They both allow us to write code logic for a group of types, instead of just one type&lt;/strong&gt;. The code logic is the &lt;em&gt;common behavior&lt;/em&gt; for those types. The binding of specific types are deferred to later times: for type erasure and virtual inheritence, this binding is defered to runtime; for C++ template and C++ concept, this binding is deferred to compile time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can write binary libraries which can be used on difference types using type erasure and virtual inheritence&lt;/li&gt;
&lt;li&gt;We can write templated source code libraries which can be used on difference types using C++ template and C++ concept&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C++ concept is more restricted C++ template. C++ virtual inheritence is special kind of type erasure, with vtable as runtime dispatch method. &lt;strong&gt;All being said, at the core, they are all function pointer binding methods, at compile time, or at runtime. When bind at runtime, it’s always during the construction phase&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type erasure of std::function
&lt;/h2&gt;

&lt;p&gt;After the signature is specified through template paramter, &lt;code&gt;std::function&lt;/code&gt; variable can be used to store difference kinds of &lt;em&gt;types&lt;/em&gt;, as long as they both have the same signature. This is done through type erasure. &lt;code&gt;std::function&lt;/code&gt; has value semantics and can be copied and moved. After the template signature is determined the code for all methods is fixed for the compiler. After a &lt;code&gt;std::function&lt;/code&gt; instance is constructed, the &lt;em&gt;implementation&lt;/em&gt; binding is fixed.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://shan-weiqiang.github.io/2025/06/29/type-erasure-part-two.html" rel="noopener noreferrer"&gt;std::function implementation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Type erasure of std::shared_ptr deleter
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;std::shared_ptr&lt;/code&gt; type use virtual base class to do type erasure. If user pass a custom deleter during construction, the pointer instance will be bound to a unified base class and points to the implementation of this custom deleter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Support for custom deleter and/or allocator
template &amp;lt;typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp&amp;gt;
class _Sp_counted_deleter final : public _Sp_counted_base&amp;lt;_Lp&amp;gt; {
  class _Impl : _Sp_ebo_helper&amp;lt;0, _Deleter&amp;gt;, _Sp_ebo_helper&amp;lt;1, _Alloc&amp;gt; {
    typedef _Sp_ebo_helper&amp;lt;0, _Deleter&amp;gt; _Del_base;
    typedef _Sp_ebo_helper&amp;lt;1, _Alloc&amp;gt; _Alloc_base;

  public:
    _Impl(_Ptr __p, _Deleter__ d, const _Alloc &amp;amp;__a) noexcept
        : _M_ptr(__p), _Del_base(std::move(__d)), _Alloc_base(__a) {}

    _Deleter &amp;amp;_M_del() noexcept { return _Del_base::_S_get(*this); }
    _Alloc &amp;amp;_M_alloc() noexcept { return _Alloc_base::_S_get(*this); }

    _Ptr _M_ptr;
  };

public:
  using __allocator_type =__ alloc_rebind&amp;lt;_Alloc, _Sp_counted_deleter&amp;gt;;

  // __d(__p) must not throw.
  _Sp_counted_deleter(_Ptr __p, _Deleter__ d) noexcept
      : _M_impl(__p, std::move(__d), _Alloc()) {}

  // __d(__p) must not throw.
  _Sp_counted_deleter(_Ptr __p, _Deleter__ d, const _Alloc &amp;amp;__a) noexcept
      : _M_impl(__p, std::move(__d), __a) {}

  ~_Sp_counted_deleter() noexcept {}

  virtual void _M_dispose() noexcept { _M_impl._M_del()(_M_impl._M_ptr); }

  virtual void _M_destroy() noexcept {
    __allocator_type__ a(_M_impl._M_alloc());
    __allocated_ptr&amp;lt;__ allocator_type&amp;gt; __guard_ptr{__ a, this};
    this-&amp;gt;~_Sp_counted_deleter();
  }

  virtual void *_M_get_deleter(const std::type_info &amp;amp;__ti) noexcept {
#if __cpp_rtti
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 2400. shared_ptr's get_deleter() should use addressof()
    return __ti == typeid(_Deleter) ? std::__addressof(_M_impl._M_del())
                                    : nullptr;
#else
    return nullptr;
#endif
  }

private:
  _Impl _M_impl;
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;_Deleter&lt;/code&gt; type is erased at compile time, &lt;code&gt;std::shared_ptr&lt;/code&gt; type will only store a pointer of &lt;code&gt;_Sp_counted_base&lt;/code&gt; type, which makes the &lt;code&gt;std::shared_ptr&lt;/code&gt; type not depend on custom deleters.&lt;/p&gt;

&lt;h2&gt;
  
  
  More about binding
&lt;/h2&gt;

&lt;p&gt;After a type is erased, we &lt;strong&gt;have to&lt;/strong&gt; bind to the correct &lt;em&gt;implementations&lt;/em&gt;. The implementation must coorespond to this type, otherwise, there will be errors if we pass a &lt;em&gt;void&lt;/em&gt; pointer to this implementation, since inside this implementation, the &lt;em&gt;void&lt;/em&gt; pointer will be cast back to this type. Of course, there can be multiple implementations for this type, &lt;strong&gt;but, there is only one binding&lt;/strong&gt;. Better use examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether it’s compile time or runtime, as long as the binding is finished, it &lt;em&gt;cannot&lt;/em&gt; be changed.&lt;/li&gt;
&lt;li&gt;For virtual class, when a derived class instance is created, it’s vtable is bound to vtable of this class, it’s &lt;em&gt;wrong&lt;/em&gt; to change it.&lt;/li&gt;
&lt;li&gt;For template functions, which binds at compile time, it’s fixed after compilation, and cannot be changed.&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;std::function&lt;/code&gt;, we can have multiple variable for the same signature: &lt;code&gt;std::function&amp;lt;int(int)&amp;gt; a&lt;/code&gt;, &lt;code&gt;std::function&amp;lt;int(int)&amp;gt;b&lt;/code&gt;, and they can have &lt;strong&gt;different&lt;/strong&gt; implementations. However, after &lt;strong&gt;construction&lt;/strong&gt; of &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, their binding to implementation is &lt;em&gt;fixed&lt;/em&gt;, we cannot change &lt;code&gt;a&lt;/code&gt;’s implementation to &lt;code&gt;b&lt;/code&gt;’s. Of course, we can assign &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;b&lt;/code&gt;, which will create a copy of &lt;code&gt;b&lt;/code&gt;, but this is &lt;em&gt;not&lt;/em&gt; changing the binding of &lt;code&gt;a&lt;/code&gt;. Even though &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are of the same type, but they contain and bind to different callables:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template &amp;lt;typename _Res, typename... _ArgTypes&amp;gt;
template &amp;lt;typename _Functor, typename, typename&amp;gt;
function&amp;lt;_Res(_ArgTypes...)&amp;gt;::function(_Functor __f) : _Function_base() {
typedef _Function_handler&amp;lt;_Res(_ArgTypes...), _Functor&amp;gt; _My_handler;

if (_My_handler::_M_not_empty_function(__f)) {
  _My_handler::_M_init_functor(_M_functor, std::move(__f));
  _M_invoker = &amp;amp;_My_handler::_M_invoke;
  _M_manager = &amp;amp;_My_handler::_M_manager;
}
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;em&gt;construction&lt;/em&gt; the binding is fixed and can not be changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  std::variant
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;std::variant&lt;/code&gt; itself is not type erasure, it’s a union and will record flags to indicate which type it currently stores&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;std::visit&lt;/code&gt; involves two phase: 

&lt;ul&gt;
&lt;li&gt;Dispatch right function according to specific type stored in std::variant at runtime&lt;/li&gt;
&lt;li&gt;Each function is stored type erased, like &lt;code&gt;std::function&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>c</category>
    </item>
    <item>
      <title>Reactor and Proactor Exectuion Context</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sat, 29 Mar 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/reactor-and-proactor-exectuion-context-3kal</link>
      <guid>https://dev.to/weiqiang/reactor-and-proactor-exectuion-context-3kal</guid>
      <description>&lt;p&gt;Following content aggregates materials about &lt;em&gt;reactor&lt;/em&gt; and &lt;em&gt;proactor&lt;/em&gt;, along with some keynotes about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/shan-weiqiang/shan-weiqiang.github.io/blob/main/assets/files/tpd_reactor_proactor.pdf" rel="noopener noreferrer"&gt;Reactor and Proactor, Examples of event handling patterns&lt;/a&gt;: Great material on what is reactor and what is proactor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shan-weiqiang/shan-weiqiang.github.io/blob/main/assets/files/The%20Proactor%20Design%20Pattern.pdf" rel="noopener noreferrer"&gt;The Proactor Design Pattern: Concurrency Without Threads&lt;/a&gt;: Explains the boost.asio proactor design pattern. What is key about this material is that it also explains the relationship between reactor and proactor in Linux: proactor is implemented on top of reactor(epoll).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Proactor_pattern" rel="noopener noreferrer"&gt;Proactor Wikipedia&lt;/a&gt;: The wiki page reveals an important fact about proactor: &lt;strong&gt;The proactor pattern can be considered to be an asynchronous variant of the synchronous reactor pattern.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keynotes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reactor in Linux has native OS support through system primitives like &lt;code&gt;epoll&lt;/code&gt;. But Linux does not have native support for proactor. Windows have native support for proactor, IOCP&lt;/li&gt;
&lt;li&gt;In Linux, proactor is implemented on top of reactor.&lt;/li&gt;
&lt;li&gt;Reactor is &lt;em&gt;synchronous&lt;/em&gt; I/O, while proactor is &lt;em&gt;asynchronous&lt;/em&gt; I/O.&lt;/li&gt;
&lt;li&gt;Again and important: &lt;strong&gt;The proactor pattern can be considered to be an asynchronous variant of the synchronous reactor pattern.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Reactor in Linux can be simplified as I/O multiplexing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Execution Context
&lt;/h2&gt;

&lt;p&gt;One thing that have long been confusing me about proactor is it’s execution context. For reactor, it occupies one execution context(eg, a thread) and blockingly waiting for any of file descriptors to be ready for relevant events. Since in Linux proactors are implemented on top of reactor, does proactor need additional execution context? In Boost, proactor is called &lt;a href="https://live.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/async.html" rel="noopener noreferrer"&gt;&lt;em&gt;The Proactor Design Pattern: Concurrency Without Threads&lt;/em&gt;&lt;/a&gt;, which indicates that there are no additional threads required for proactor. Then how to implement proactor in one thread, knowing that reactor itself already occupies one thread?&lt;/p&gt;

&lt;p&gt;The foundation here is to know that(in the context of &lt;code&gt;boost.asio&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a underlying reactor, which is normally implemented using &lt;code&gt;epoll&lt;/code&gt; in Linux.&lt;/li&gt;
&lt;li&gt;There is one execution context, &lt;code&gt;io_context&lt;/code&gt;, which will be called in one thread &lt;code&gt;io_context.run()&lt;/code&gt;, which will call &lt;code&gt;epoll&lt;/code&gt; wait under the hood.&lt;/li&gt;
&lt;li&gt;That &lt;code&gt;epoll&lt;/code&gt; can monitor multiple file descriptors and can be updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet there is one brick missing to understanding the proactor pattern: &lt;em&gt;software events&lt;/em&gt;. Epoll can only monitor file descriptors, like if a file descriptor is readable, writable, etc. But proactor requires that the &lt;em&gt;epoll_wait&lt;/em&gt; be unblocked if a user async operation is completed. How can epoll monitor these kinds of events? In the reactor that is used to implement proactor, there is an pre-defined additional file descriptor, it might be a pipe, uds socket, or something else, as long as it can be written and read. This fd is used to unblock &lt;em&gt;epoll_wait&lt;/em&gt; whenever there is software events. For example, &lt;em&gt;epoll_wait&lt;/em&gt; monitor this fd, &lt;em&gt;fd_events&lt;/em&gt; and another socket fd, &lt;em&gt;fd_socket&lt;/em&gt;. &lt;em&gt;fd_socket&lt;/em&gt; is to read bytes from a connection. &lt;em&gt;fd_events&lt;/em&gt; is a, for example, pipe. There is a async reading operation initiated by user to read n bytes from &lt;em&gt;fd_socket&lt;/em&gt;, and also a completion handler is provided and registered. Now the &lt;em&gt;epoll_wait&lt;/em&gt; is blocked waiting to read from &lt;em&gt;fd_socket&lt;/em&gt;, and the execution context thread is suspended in OS. Now n-1 bytes are recieved from kernel and is ready to be read. The &lt;em&gt;epoll_wait&lt;/em&gt; is unblocked and find that &lt;em&gt;fd_socket&lt;/em&gt; is ready to read from. The reactor calls relevant callbacks to read from this socket. Since the callback only read n-1 bytes, not n bytes, which is required by the async operation, it exit the loop and give control to &lt;em&gt;epoll_wait&lt;/em&gt; again. Next, the last one byte finally arrived, again the &lt;em&gt;epoll_wait&lt;/em&gt; is unblocked and the registered callback is called to read the last one byte. After reading, inside the callback, it knows that the operation is finally completed as required from the async operation. It now writes the completion information to the &lt;em&gt;fd_events&lt;/em&gt; and exit the loop to go back to &lt;em&gt;epoll_wait&lt;/em&gt; again. This time the &lt;em&gt;epoll_wait&lt;/em&gt; immediately unblocks since there are content to be read from &lt;em&gt;fd_events&lt;/em&gt;, software events happen. The reactor calls relevant software events callback and process the software events. Inside the callback, it first read from the &lt;em&gt;fd_events&lt;/em&gt; and knows which software events happen and according to the information,it finds the corresponding completion handler and executes it. It goes on until all completed software events handlers are executed, then goes to &lt;em&gt;epoll_wait&lt;/em&gt; again.&lt;/p&gt;

&lt;p&gt;Let’s understand above process with the help of following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include "make_day_time.h"
#include &amp;lt;asio.hpp&amp;gt;
#include &amp;lt;memory&amp;gt;

#ifndef ASYNC_UDP
#define ASYNC_UDP

using asio::ip::udp;
class udp_server {
public:
  udp_server(asio::io_context &amp;amp;io_context)
      : socket_(io_context, udp::endpoint(udp::v4(), 5002)) {
    start_receive();
  }

private:
  udp::socket socket_;
  udp::endpoint remote_endpoint;
  std::array&amp;lt;char, 1&amp;gt; buffer;

  void start_receive() {
    socket_.async_receive_from(
        asio::buffer(buffer), remote_endpoint,
        [this](const std::error_code &amp;amp;error, std::size_t) {
          if (!error) {
            std::shared_ptr&amp;lt;std::string&amp;gt; msg =
                std::make_shared&amp;lt;std::string&amp;gt;(make_daytime_string());
            socket_.async_send_to(
                asio::buffer(*msg), remote_endpoint,
                [](const std::error_code &amp;amp;error, std::size_t) {});
            start_receive();
          }
        });
  }
};

#endif

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;io_context&lt;/code&gt; serves as the sole execution context. It will be run inside one thread. The reactor is implemented inside &lt;code&gt;asio::io_context&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;socket_.async_receive_from&lt;/code&gt; is the asyn operation initialized from user. It provides two requirements: 

&lt;ul&gt;
&lt;li&gt;The receive operation should fill the buffer&lt;/li&gt;
&lt;li&gt;After the buffer is filled, the lambda completion handler should be called Inside this call, it will register: &lt;/li&gt;
&lt;li&gt;Monitoring of this socket to &lt;code&gt;io_context&lt;/code&gt;, when it’s available to read, epoll will unblock. &lt;strong&gt;Note that after the reading is completed, inside the callback registered to the reactor, it will deregister the monitoring of this socket from the reactor. Then also inside the callback, it will trigger software events to make the execution context execute completion handler in next loop of &lt;em&gt;epoll_wait&lt;/em&gt;.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Register software event and it’s handler(the lambda) to this same &lt;code&gt;io_context&lt;/code&gt;, expecting it to be called when the reading is completed. This call returns immediately.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Inside the lambda, &lt;code&gt;socket_.async_send_to&lt;/code&gt; is called to give feedback. Again it’s the same pattern as &lt;code&gt;socket_.async_receive_from&lt;/code&gt; , except that this time the reactor will unblock when this socket is available to write. After the writing complete, the completion lambda is again called as software event.&lt;/li&gt;

&lt;li&gt;Inside the &lt;code&gt;socket_.async_send_to&lt;/code&gt; completion handler, &lt;code&gt;start_receive();&lt;/code&gt; is called recursively, which starts the loop again.&lt;/li&gt;

&lt;li&gt;Note that the send-recieve-send-recieve is executed in order.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Do not call async read and write operations before the last one is completed. There is no meaning to do that anyway:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interleaved read/write is meaningless, even if it is possible(I don’t know if it is possible in &lt;code&gt;asio&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Even if the async operations are queued by &lt;code&gt;asio&lt;/code&gt;(again I don’t know if it is the case in &lt;code&gt;asio&lt;/code&gt;), we can chain the read/write in completion handlers to have the same effect.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>Expressions: type and value category</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Fri, 28 Feb 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/expressions-type-and-value-category-13cf</link>
      <guid>https://dev.to/weiqiang/expressions-type-and-value-category-13cf</guid>
      <description>&lt;p&gt;According to my experience, the most difficult part in understanding C++ is however the most basic one: the &lt;code&gt;expression&lt;/code&gt;. Only by having a comprehensive understanding of &lt;code&gt;expression&lt;/code&gt;, one can further have a clear understanding about lvalue, rvalue, type deduction, &lt;code&gt;auto&lt;/code&gt; keyword, universal reference, &lt;code&gt;decltype&lt;/code&gt;, move semantics,etc. As you can see, above-mentioned concepts are at the core of C++ 11 and afterwards.&lt;/p&gt;

&lt;p&gt;This blog summarize information, concepts, references around &lt;code&gt;expression&lt;/code&gt;. It does not provide additional knowledge, but act as a understanding note.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Expressions

&lt;ul&gt;
&lt;li&gt;Type&lt;/li&gt;
&lt;li&gt;Value Category&lt;/li&gt;
&lt;li&gt;Type vs ValueCategory&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Type Deduction

&lt;ul&gt;
&lt;li&gt;Deduction context&lt;/li&gt;
&lt;li&gt;Function template parameter type deduction&lt;/li&gt;
&lt;li&gt;auto deduction&lt;/li&gt;
&lt;li&gt;More about Universal Reference&lt;/li&gt;
&lt;li&gt;Reference Collapsing Rules&lt;/li&gt;
&lt;li&gt;Key Points &amp;amp; Golden Rules&lt;/li&gt;
&lt;li&gt;std::forward explained&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Named Variables&lt;/li&gt;

&lt;li&gt;

decltype

&lt;ul&gt;
&lt;li&gt;Print valueness&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;static_cast vs decltype&lt;/li&gt;

&lt;li&gt;declval&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Expressions
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://en.cppreference.com/w/cpp/language/expressions" rel="noopener noreferrer"&gt;C++ expressions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category. Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories: &lt;em&gt;prvalue&lt;/em&gt;, &lt;em&gt;xvalue&lt;/em&gt;, and &lt;em&gt;lvalue&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type
&lt;/h2&gt;

&lt;p&gt;An expression can have basic type, user-defined type, const/non-const, reference/non-reference types. However, &lt;strong&gt;If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis.&lt;/strong&gt;, which indicates that expression can have reference types. &lt;a href="https://scottmeyers.blogspot.com/2015/02/expressions-can-have-reference-type.html" rel="noopener noreferrer"&gt;Expressions can have Reference Type&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Today I got email about some information in &lt;em&gt;Effective Modern C++&lt;/em&gt;. The email included the statement, “An expression never has reference type.” This is easily shown to be incorrect, but people assert it to me often enough that I’m writing this blog entry so that I can refer people to it in the future.&lt;/p&gt;

&lt;p&gt;Section 5/5 of the Standard is quite clear (I’ve put the relevant text in bold):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If an expression initially has the type “reference to T”&lt;/strong&gt; (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There’d clearly be no need for this part of the Standard if expressions couldn’t have reference type.&lt;/p&gt;

&lt;p&gt;If that’s not enough to settle the matter, consider the type of an expression that consists of a function call. For example:&lt;/p&gt;



&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int&amp;amp; f(); // f returns int&amp;amp;
auto x = f(); // a call to f


&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;What is the type of the expression “f()”, i.e., the type of the expression consisting of a call to f? It’s hard to imagine anybody arguing that it’s not int&amp;amp;, i.e., a reference type. But what does the Standard say? Per 5.2.2/3 (where I’ve again put the relevant text in bold and where I’m grateful to Marcel Wid for correcting the error I had in an earlier version of this post that referred to 5.2.2/10):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the &lt;em&gt;postfix-expression&lt;/em&gt; designates a destructor (12.4), the type of the function call expression is void; otherwise, &lt;strong&gt;the type of the function call expression is the return type of the statically chosen function&lt;/strong&gt; (i.e., ignoring the virtual keyword), even if the type of the function actually called is different. This return type shall be an object type, &lt;strong&gt;a reference type&lt;/strong&gt; or cv void.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s very clear that expressions can have reference type. Section 5/5 takes those expressions and strips the reference-ness off of them before doing anything else, but that’s not the same as the reference-ness never being present in the first place.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Value Category
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.cppreference.com/w/cpp/language/value_category" rel="noopener noreferrer"&gt;C++ value_category&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With the introduction of move semantics in C++11, value categories were redefined to characterize two independent properties of expressions&lt;a href="https://en.cppreference.com/w/cpp/language/value_category#cite_note-5" rel="noopener noreferrer"&gt;[5]&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;has identity&lt;/em&gt;: it’s possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly);&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;can be moved from&lt;/em&gt;: &lt;a href="https://en.cppreference.com/w/cpp/language/move_constructor" rel="noopener noreferrer"&gt;move constructor&lt;/a&gt;, &lt;a href="https://en.cppreference.com/w/cpp/language/move_assignment" rel="noopener noreferrer"&gt;move assignment operator&lt;/a&gt;, or another function overload that implements move semantics can bind to the expression.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In C++11, expressions that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have identity and cannot be moved from are called &lt;em&gt;lvalue&lt;/em&gt; expressions;&lt;/li&gt;
&lt;li&gt;have identity and can be moved from are called &lt;em&gt;xvalue&lt;/em&gt; expressions;&lt;/li&gt;
&lt;li&gt;do not have identity and can be moved from are called &lt;em&gt;prvalue&lt;/em&gt; (“pure rvalue”) expressions;&lt;/li&gt;
&lt;li&gt;do not have identity and cannot be moved from are not used&lt;a href="https://en.cppreference.com/w/cpp/language/value_category#cite_note-6" rel="noopener noreferrer"&gt;[6]&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The expressions that have identity are called “glvalue expressions” (glvalue stands for “generalized lvalue”). Both lvalues and xvalues are glvalue expressions.&lt;/p&gt;

&lt;p&gt;The expressions that can be moved from are called “rvalue expressions”. Both prvalues and xvalues are rvalue expressions.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ____________

  / X \

 / / \ \

| l | x | pr |

 \ \ / /

  \ ______X______ /

​ gl r

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above diagram describes the general relationship between &lt;em&gt;lvalue&lt;/em&gt;(l), &lt;em&gt;xvalue&lt;/em&gt;(x), &lt;em&gt;prvalue&lt;/em&gt;(pr), &lt;em&gt;glvalue&lt;/em&gt;(gl), &lt;em&gt;rvalue&lt;/em&gt;(r)&lt;/p&gt;

&lt;h2&gt;
  
  
  Type vs ValueCategory
&lt;/h2&gt;

&lt;p&gt;Lvalueness or rvalueness of an expression is independent of its type, it’s possible to have lvalues whose type is rvalue reference, and it’s also possible to have rvalues of the type rvalue reference. See examples from &lt;a href="https://github.com/shan-weiqiang/cplusplus/blob/main/expression/universal-references-and-reference-collapsing-scott-meyers.pdf" rel="noopener noreferrer"&gt;Universal References in C++11, Scott Meyers&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Widget makeWidget();
 // factory function for Widget
Widget&amp;amp;&amp;amp; var1 = makeWidget()
 // var1 is an lvalue, but
 // its type is rvalue reference (to Widget)
Widget var2 = static_cast&amp;lt;Widget&amp;amp;&amp;amp;&amp;gt;(var1);
 // the cast expression yields an rvalue, but
 // its type is rvalue reference (to Widget)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the valueness of expression &lt;code&gt;static_cast&lt;/code&gt; is decided by &lt;a href="https://en.cppreference.com/w/cpp/language/static_cast" rel="noopener noreferrer"&gt;&lt;code&gt;static_cast&lt;/code&gt;&lt;/a&gt; itself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As with all cast expressions, the result is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An lvalue if target-type is an lvalue reference type or an rvalue reference to function type(since C++11);&lt;/li&gt;
&lt;li&gt;A xvalue if target-type is an rvalue reference to object type; &lt;a href="https://dev.tosince%20C++11"&gt;swq: how &lt;code&gt;std::move&lt;/code&gt; is implemented&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A prvalue otherwise.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Type Deduction
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Deduction context
&lt;/h2&gt;

&lt;p&gt;We consider two occasions where type deduction happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="(https://en.cppreference.com/w/cpp/language/template_argument_deduction)."&gt;Function template parameter type deduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, a special kind of type deduction, universal reference is considered.&lt;/p&gt;

&lt;p&gt;During compile time compiler has mainly two ways to deduce template parameter types: from user and auto deduction. In the case of user input, whatever user specifies, compiler will use them. If user specified reference, reference collapsing rules apply. Also in C++ 17, class template parameter type can also be deduced: &lt;a href="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction" rel="noopener noreferrer"&gt;Class template argument deduction (CTAD) (since C++17)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function template parameter type deduction
&lt;/h2&gt;

&lt;p&gt;Note: Most content of this paragraph comes from the book: &lt;em&gt;Effective Modern C++, Scott Meyers&lt;/em&gt;. I only copies them here to make this artical complete.&lt;/p&gt;

&lt;p&gt;Take:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(ParamType param);
f(expr); // deduce T and ParamType from expr

// Above pseudo code can represent most cases, since reference, const are not allowed insdie parameter list: template&amp;lt;typename const T&amp;gt; and template&amp;lt;typename T&amp;amp;&amp;gt; and template&amp;lt;typename T&amp;amp;&amp;amp;&amp;gt; are both not valid. However, when user specify T, const and reference types can be used and reference collapsing rules apply.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;typename&lt;/code&gt; can only be &lt;code&gt;class&lt;/code&gt;, or &lt;code&gt;typename&lt;/code&gt;, no additional qualifiers are possible: &lt;a href="https://en.cppreference.com/w/cpp/language/template_parameters" rel="noopener noreferrer"&gt;type-parameter-key -either typename or class&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Case 1: ParamType is a Reference or Pointer, but not a Universal Reference 

&lt;ul&gt;
&lt;li&gt;If expr’s type is a reference, ignore the reference part&lt;/li&gt;
&lt;li&gt;Then pattern-match expr’s type against ParamType to determine T.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Case 2: ParamType is a Universal Reference 

&lt;ul&gt;
&lt;li&gt;If expr is an lvalue, both T and ParamType are deduced to be lvalue references. That’s doubly unusual. First, it’s the only situation in template type deduction where T is deduced to be a reference. Second, although ParamType is declared using the syntax for an rvalue reference, its deduced type is an lvalue reference.&lt;/li&gt;
&lt;li&gt;If expr is an rvalue, the “normal” (i.e., Case 1) rules apply.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Case 3: ParamType is Neither a Pointer nor a Reference 

&lt;ul&gt;
&lt;li&gt;As before, if expr’s type is a reference, ignore the reference part&lt;/li&gt;
&lt;li&gt;If, after ignoring expr’s reference-ness, expr is const, ignore that, too. If it’s volatile, also ignore that.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  auto deduction
&lt;/h2&gt;

&lt;p&gt;It’s essentially the same as function template parameter type deduction like above, the mappings relationships are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;auto&lt;/code&gt; –&amp;gt; &lt;code&gt;T&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Expression before &lt;code&gt;=&lt;/code&gt; –&amp;gt; &lt;code&gt;ParamType&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Expression after &lt;code&gt;=&lt;/code&gt; –&amp;gt; &lt;code&gt;expr&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;auto x = 27; // case 3 (x is neither ptr nor reference)
const auto cx = x; // case 3 (cx isn't either)
const auto&amp;amp; rx = x; // case 1 (rx is a non-universal ref.)
// T --&amp;gt; auto; const auto&amp;amp; --&amp;gt; ParamType; x --&amp;gt; expr

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;auto&lt;/code&gt; can also be used in lamda and support universal reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;iterator&amp;gt;
#include &amp;lt;utility&amp;gt;
#include &amp;lt;vector&amp;gt;

class A {
public:
  // Default constructor
  A() { std::cout &amp;lt;&amp;lt; "Default constructor called\n"; }

  // Destructor
  ~A() { std::cout &amp;lt;&amp;lt; "Destructor called\n"; }

  // Copy constructor
  A(const A &amp;amp;) { std::cout &amp;lt;&amp;lt; "Copy constructor called\n"; }

  // Move constructor
  A(A &amp;amp;&amp;amp;) noexcept { std::cout &amp;lt;&amp;lt; "Move constructor called\n"; }

  // Copy assignment operator
  A &amp;amp;operator=(const A &amp;amp;) {
    std::cout &amp;lt;&amp;lt; "Copy assignment operator called\n";
    return *this;
  }

  // Move assignment operator
  A &amp;amp;operator=(A &amp;amp;&amp;amp;) noexcept {
    std::cout &amp;lt;&amp;lt; "Move assignment operator called\n";
    return *this;
  }
};

int main() {

  std::vector&amp;lt;A&amp;gt; vec(2);
  std::for_each(vec.begin(), vec.end(),
                // e is of lvalue, copy contructor called
                // Note: e is not expression here, decltype get the real type of
                // e, for universal reference, it's either non-reference type or
                // lvalue reference type
                [](auto &amp;amp;&amp;amp;e) { auto a = std::forward&amp;lt;decltype(e)&amp;gt;(e); });

  std::for_each(std::make_move_iterator(vec.begin()),
                std::make_move_iterator(vec.end()),
                // e is of xvalue, move contructor called
                // Note: e is not expression here, decltype get the real type of
                // e, for universal reference, it's either non-reference type or
                // lvalue reference type
                [](auto &amp;amp;&amp;amp;e) { auto a = std::forward&amp;lt;decltype(e)&amp;gt;(e); });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  More about Universal Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/shan-weiqiang/cplusplus/blob/main/expression/universal-references-and-reference-collapsing-scott-meyers.pdf" rel="noopener noreferrer"&gt;Universal References in C++11, Scott Meyers&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference Collapsing Rules
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.cppreference.com/w/cpp/language/reference" rel="noopener noreferrer"&gt;C++ Reference&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An rvalue reference to an rvalue reference becomes (‘collapses into’) an rvalue reference.&lt;/li&gt;
&lt;li&gt;All other references to references (i.e., all combinations involving an lvalue reference) collapse into an lvalue reference.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Points &amp;amp; Golden Rules
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Remember that “&amp;amp;&amp;amp;” indicates a universal reference only where type deduction takes place. Where there’s no type deduction, there’s no universal reference. In such cases, “&amp;amp;&amp;amp;” in type declarations always means rvalue reference.&lt;/li&gt;
&lt;li&gt;Apply std::move to rvalue references and std::forward to universal references&lt;/li&gt;
&lt;li&gt;Only use std::forward with universal references&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Universal reference type deduction is the only situation a template parameter is deduced as reference(when passed type is of lvalue).&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  std::forward explained
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.cppreference.com/w/cpp/utility/forward" rel="noopener noreferrer"&gt;std::forward&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only use &lt;code&gt;std::forward&lt;/code&gt; with universal reference. So the template argument for it should always be deduced, instead of specified. 

&lt;ul&gt;
&lt;li&gt;This implies that the deduced type T is either non-reference type or a lvalue reference.&lt;/li&gt;
&lt;li&gt;Always use universal reference template paramter &lt;code&gt;T&lt;/code&gt; &lt;strong&gt;directly&lt;/strong&gt; for &lt;code&gt;std::forward&lt;/code&gt;’s template paramters, do not manually add additional const/reference to it. Note that &lt;code&gt;T&lt;/code&gt; can be decorated: like &lt;code&gt;forward&amp;lt;decltype(forward&amp;lt;T&amp;gt;(arg).get())&amp;gt;&lt;/code&gt;, as long as &lt;code&gt;T&lt;/code&gt; itself is the same as the universal reference.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;std::forward&lt;/code&gt; is an &lt;em&gt;expression&lt;/em&gt; and &lt;em&gt;function&lt;/em&gt;, it’s value category conform to normal C++ expression rules. It always return &lt;em&gt;reference&lt;/em&gt;: 

&lt;ul&gt;
&lt;li&gt;When return lvalue reference, its value category is lvalue&lt;/li&gt;
&lt;li&gt;When return rvalue reference, its value category is rvalue(xvalue or prvalue)&lt;/li&gt;
&lt;li&gt;Above behavior is due to the fact that when cast to rvalue reference, the result of &lt;code&gt;static_cast&lt;/code&gt; is of xvalue; when cast to non-reference, the result is of prvalue; when cast to lvalue reference, the result is of lvalue.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The type and valueness is decided by &lt;code&gt;static_cast&lt;/code&gt;, which is the internal implementation of &lt;code&gt;std::forward&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The standard implements &lt;code&gt;std::forward&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  /**
   * @brief Forward an lvalue.
   * @return The parameter cast to the specified type.
   *
   * This function is used to implement "perfect forwarding".
   */
  template&amp;lt;typename _Tp&amp;gt;
    constexpr _Tp&amp;amp;&amp;amp;
    forward(typename std::remove_reference&amp;lt;_Tp&amp;gt;::type&amp;amp; __t) noexcept
    { return static_cast&amp;lt;_Tp&amp;amp;&amp;amp;&amp;gt;(__t); }

  /**
   * @brief Forward an rvalue.
   * @return The parameter cast to the specified type.
   *
   * This function is used to implement "perfect forwarding".
   */
  template&amp;lt;typename _Tp&amp;gt;
    constexpr _Tp&amp;amp;&amp;amp;
    forward(typename std::remove_reference&amp;lt;_Tp&amp;gt;::type&amp;amp;&amp;amp; __t) noexcept
    {
      static_assert(!std::is_lvalue_reference&amp;lt;_Tp&amp;gt;::value, "template argument"
            " substituting _Tp is an lvalue reference type");
      return static_cast&amp;lt;_Tp&amp;amp;&amp;amp;&amp;gt;(__t);
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;_Tp&lt;/code&gt; is the type deduced from universal references, which might be non-reference type or lvalue reference type. &lt;code&gt;__t&lt;/code&gt; is the parameter passed to &lt;code&gt;std::forward&lt;/code&gt;, which is of lvalue category, since inside function, parameters are passed always as lvalues. The aim of &lt;code&gt;std::forward&lt;/code&gt; is to restore the value category of the passed parameter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;_Tp&lt;/code&gt; is of non-reference type, which means the universal reference is deduced based on passed rvalue parameter: 

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;__t&lt;/code&gt; is of &lt;code&gt;_Tp&amp;amp;&amp;amp;&lt;/code&gt; type, the second overload is used, &lt;code&gt;std::forward&lt;/code&gt; return rvalue category, rvalue reference type object&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When &lt;code&gt;_Tp&lt;/code&gt; is of lvalue reference type, which means the universal reference is deduced based on passed lvalue parameter: 

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;__t&lt;/code&gt; is of &lt;code&gt;_Tp&amp;amp;&lt;/code&gt; type, the first overload is used, &lt;code&gt;std::forward&lt;/code&gt; return lvalue category, lvalue reference type object&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Note: &lt;strong&gt;Type is not changed when parameters are passed down to nested function calls, only value category are changed. This is how &lt;code&gt;std:forward&lt;/code&gt; do overload based on types&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usage1: Forwards lvalues as either lvalues or as rvalues, depending on T:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template&amp;lt;class T&amp;gt;
void wrapper(T&amp;amp;&amp;amp; arg)
{
    // arg is always lvalue
    foo(std::forward&amp;lt;T&amp;gt;(arg)); // Forward as lvalue or as rvalue, depending on T
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When T is deduced to non-reference type,the expression &lt;code&gt;std::forward&lt;/code&gt; is of: 

&lt;ul&gt;
&lt;li&gt;type: rvalue reference to T&lt;/li&gt;
&lt;li&gt;value category: rvalue&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When T is deduced to lvalue reference type, the expression &lt;code&gt;std::forward&lt;/code&gt; is of: 

&lt;ul&gt;
&lt;li&gt;type: lvalue reference to T&lt;/li&gt;
&lt;li&gt;value category: lvalue&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Note: &lt;strong&gt;This usage is to restore the value category of the passed parameter, whose valueness, due to the nested argument passing, is all treated as lvalue category.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usage2: Forwards rvalues as rvalues and prohibits forwarding of rvalues as lvalues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct Arg
{
    int i = 1;
    int get() &amp;amp;&amp;amp; { return i; } // call to this overload is rvalue
    int&amp;amp; get() &amp;amp; { return i; } // call to this overload is lvalue
};
// transforming wrapper
template&amp;lt;class T&amp;gt;
void wrapper(T&amp;amp;&amp;amp; arg)
{
    foo(forward&amp;lt;decltype(forward&amp;lt;T&amp;gt;(arg).get())&amp;gt;(forward&amp;lt;T&amp;gt;(arg).get()));
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;decltype(forward&amp;lt;T&amp;gt;(arg).get())&lt;/code&gt; evalues the type: 

&lt;ul&gt;
&lt;li&gt;If T is deduced to non-reference type, the expression &lt;code&gt;forward&amp;lt;T&amp;gt;(arg).get()&lt;/code&gt; will have type &lt;code&gt;int&lt;/code&gt; and have xvalueness. &lt;code&gt;decltype&lt;/code&gt; will result in type &lt;code&gt;int&amp;amp;&amp;amp;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If T is deduced to lvalue reference type, the expression &lt;code&gt;forward&amp;lt;T&amp;gt;(arg).get()&lt;/code&gt; will have type &lt;code&gt;int&amp;amp;&lt;/code&gt; and have lvalueness. &lt;code&gt;decltype&lt;/code&gt; will result int type &lt;code&gt;int&amp;amp;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The second appearance of &lt;code&gt;forward&amp;lt;T&amp;gt;(arg).get()&lt;/code&gt; just call proper implementation of &lt;code&gt;get()&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Note: when using &lt;code&gt;decltype&lt;/code&gt; as parameter argument to &lt;code&gt;std::forward&lt;/code&gt;, we only need to care about whether the expression in &lt;code&gt;decltype&lt;/code&gt; is lvalue or rvalue, no need to care about the type(only need to know the non-reference type of T). Since if the expression is lvalue, &lt;code&gt;decltype&lt;/code&gt; will result in lvalue reference type, which result in lvalue reference type(lvalueness) for the &lt;code&gt;std::forward&lt;/code&gt;. Otherwise, if the expression inside &lt;code&gt;decltype&lt;/code&gt; is of xvalue or prvalue, &lt;code&gt;decltype&lt;/code&gt; results in non-reference type or rvalue reference type, which both result in a rvalue reference type(rvalueness) for the &lt;code&gt;std::forward&lt;/code&gt; expression. &lt;code&gt;decltype&lt;/code&gt; and &lt;code&gt;std::forward&lt;/code&gt; together to pass the valueness down to nested function calls.&lt;/p&gt;

&lt;p&gt;Note: If we use &lt;code&gt;foo(forward&amp;lt;int&amp;amp;&amp;gt;(forward&amp;lt;T&amp;gt;(arg).get()));&lt;/code&gt; and pass a rvalue of &lt;code&gt;Arg&lt;/code&gt; instance to &lt;code&gt;wrapper&lt;/code&gt;, there will be compile time error, since we try to forward rvalue as lvalue(the valueness of the return of &lt;code&gt;std::forward&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;std::forward&lt;/code&gt; can be used together with &lt;code&gt;auto&amp;amp;&amp;amp;&lt;/code&gt; in lambdas, which needs the help of &lt;code&gt;decltype&lt;/code&gt; to infer the correct type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  std::vector&amp;lt;std::string&amp;gt; source = {"a", "b", "c"};

  // This is totally generic
  auto forwarder = [](auto &amp;amp;&amp;amp;container) {
    // If container is of lvalue, it's type is lvalue reference type, decltype
    // return lvalue reference.
    // If container is of rvalue, it's type is rvalue reference type, decltype
    // return rvalue reference
    auto dest = std::forward&amp;lt;decltype(container)&amp;gt;(container);
  };

  forwarder(std::move(source));
  std::cout &amp;lt;&amp;lt; source.size() &amp;lt;&amp;lt; std::endl;

  std::vector&amp;lt;std::string&amp;gt; source2 = {"x", "y", "z"};
  forwarder(source2);
  std::cout &amp;lt;&amp;lt; source2.size() &amp;lt;&amp;lt; std::endl;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, using of &lt;code&gt;std::forward&lt;/code&gt; in range-based for loop with &lt;code&gt;auto&amp;amp;&amp;amp;&lt;/code&gt; will not work as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  std::vector&amp;lt;std::string&amp;gt; source = {"a", "b", "c"};

  // item is std::string&amp;amp; type, even with std::move
  for (auto &amp;amp;&amp;amp;item : std::move(source)) {
    // After std::forward the return type is still std::string&amp;amp;
    auto dst = std::forward&amp;lt;decltype(item)&amp;gt;(item);
  }
  std::cout &amp;lt;&amp;lt; source[0] &amp;lt;&amp;lt; std::endl;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In above code snippet, &lt;code&gt;std::move(source)&lt;/code&gt; will not trigger move operation for &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;item&lt;/code&gt; is of lvalue category and lvalue reference type. This behavior can be explained by looking at the internal &lt;a href="https://en.cppreference.com/w/cpp/language/range-for" rel="noopener noreferrer"&gt;implementation of range-based for&lt;/a&gt; in C++:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{

auto&amp;amp;&amp;amp; /* range */ = range-initializer ﻿;
for (auto /* begin */ = /* begin-expr */, /* end */ = /* end-expr */;
/* begin */ != /* end */; ++/* begin */)
{
item-declaration = */* begin */;
statement
}
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;First the &lt;code&gt;auto&amp;amp;&amp;amp;&lt;/code&gt; universal reference is used to create a local variable, which is itself a lvalue&lt;/li&gt;
&lt;li&gt;Then use iterator to iterate over this lvalue and dereference this lvalue and create a local variable using &lt;code&gt;item-declaration&lt;/code&gt;, which is the user specified &lt;code&gt;auto &amp;amp;&amp;amp;item&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auto &amp;amp;&amp;amp;item&lt;/code&gt; will always be deduced as lvalue reference&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;auto item&lt;/code&gt; is used, &lt;code&gt;item&lt;/code&gt; will be a copy, and the original &lt;code&gt;const&lt;/code&gt; qualifier will be removed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To iterate and move element out of a container, move iterators can be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  std::vector&amp;lt;std::string&amp;gt; source = {"a", "b", "c"};

  // This will move the element
  for (auto it = std::make_move_iterator(source.begin());
       it != std::make_move_iterator(source.end()); ++it) {
    auto dst = *it;
  }
  std::cout &amp;lt;&amp;lt; source[0] &amp;lt;&amp;lt; std::endl;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Named Variables
&lt;/h1&gt;

&lt;p&gt;Named variables and parameters of rvalue reference type are lvalues. Also from &lt;a href="https://github.com/shan-weiqiang/cplusplus/blob/main/expression/universal-references-and-reference-collapsing-scott-meyers.pdf" rel="noopener noreferrer"&gt;Universal References in C++11, Scott Meyers&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
class Widget {
 ...
 Widget(Widget&amp;amp;&amp;amp; rhs);
 // rhs's type is rvalue reference, but rhs
 // itself is an lvalue
 ...
};
template&amp;lt;typename T1&amp;gt;
class Gadget {
 ...
 template &amp;lt;typename T2&amp;gt;
 Gadget(T2&amp;amp;&amp;amp; rhs);
 // rhs is a universal reference whose type will
 // eventually become an rvalue reference or an
 // lvalue reference, but rhs itself is an lvalue
 ...
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create rvalue, &lt;code&gt;std::move&lt;/code&gt;, &lt;code&gt;std::forward&lt;/code&gt;, &lt;code&gt;static_cast&lt;/code&gt; specifier has to be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;utility&amp;gt;
class A {
public:
  // Default constructor
  A() { std::cout &amp;lt;&amp;lt; "Default constructor called\n"; }

  // Destructor
  ~A() { std::cout &amp;lt;&amp;lt; "Destructor called\n"; }

  // Copy constructor
  A(const A &amp;amp;) { std::cout &amp;lt;&amp;lt; "Copy constructor called\n"; }

  // Move constructor
  A(A &amp;amp;&amp;amp;) noexcept { std::cout &amp;lt;&amp;lt; "Move constructor called\n"; }

  // Copy assignment operator
  A &amp;amp;operator=(const A &amp;amp;) {
    std::cout &amp;lt;&amp;lt; "Copy assignment operator called\n";
    return *this;
  }

  // Move assignment operator
  A &amp;amp;operator=(A &amp;amp;&amp;amp;) noexcept {
    std::cout &amp;lt;&amp;lt; "Move assignment operator called\n";
    return *this;
  }
};

int main() {

  A a;
  A &amp;amp;&amp;amp;b = std::move(a);

  // ! This will call copy constructor, NOT move constructor, even b is rvalue
  // reference type, but it's lvalue
  A c(b);

  // ! This will call move constructor
  A d(std::move(c));
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  decltype
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://en.cppreference.com/w/cpp/language/decltype" rel="noopener noreferrer"&gt;C++ decltype&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inspects the declared type of an entity or the type and value category of an expression. This implies two funtionality of decltype:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When used as decltype ( entity ), where entity is unparenthesized id-expression or class memeber expression, it yields the type of entity&lt;/li&gt;
&lt;li&gt;When used as decltype ( expression ), where expression is any other expression, it inspects the expression’s value type(eg,T) and value category and yields following types accordingly:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;if value category of expression is xvalue, it yields T&amp;amp;&amp;amp;&lt;/li&gt;
&lt;li&gt;if value category of expression is lvalue, it yields T&amp;amp;&lt;/li&gt;
&lt;li&gt;if value category of expression is prvalue, it yields T&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: if variable id-expression or class memeber access expression is parenthesized, it is treated as ordinary lvalue expression(which is reasonable, because named variables are always lvalue expressions)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Widget {};
Widget makeWidget() { return Widget(); }

int main() {

  Widget &amp;amp;&amp;amp;var1 = makeWidget();
  // var1 is an lvalue, but
  // its type is rvalue reference (to Widget)
  Widget var2 = static_cast&amp;lt;Widget &amp;amp;&amp;amp;&amp;gt;(var1);
  // the cast expression yields an rvalue, but
  // its type is rvalue reference (to Widget)
  decltype(static_cast&amp;lt;Widget &amp;amp;&amp;amp;&amp;gt;(var1)) var3 = makeWidget();
  // expression type is Widget &amp;amp;&amp;amp;, value category of expression is xvalue,
  // first get the non-reference type Widget, so var3 is of Widget&amp;amp;&amp;amp; type.
  Widget &amp;amp;var4 = var2;
  decltype(std::move(var4)) var5 = makeWidget();
  // expression type is Widget &amp;amp;, value category of expression is xvalue; first
  // get the non-reference type Widget, so var5 is of Widget &amp;amp;&amp;amp; type

  decltype((var4)) var6 = var2;
  // expression type is Widget &amp;amp;, value category of expression is lvalue; first
  // get the non-reference type Widget, so var6 is of Widget &amp;amp; type

  decltype(makeWidget()) var7 = makeWidget();
  // expression type is Widget , value category of expression is prvalue; first
  // get the non-reference type Widget, so var6 is of Widget type
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: When doing all deduction the expression type &lt;code&gt;T&lt;/code&gt; will use the non-reference version, since as the standard says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;decltype&lt;/code&gt; links valueness of an expression to type.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Print valueness
&lt;/h2&gt;

&lt;p&gt;First approach, we can check whether the yield type of decltype(expression) is lvalue or rvalue reference, if rvalue reference, the expression is xvalue; if lvalue reference, the expression is lvalue; otherwise, the expression is prvalue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;utility&amp;gt; // for std::move

class Widget {};
Widget makeWidget() { return Widget(); }

template &amp;lt;typename T&amp;gt; struct value_category {
  static constexpr const char *str() { return "prvalue"; }
};

template &amp;lt;typename T&amp;gt; struct value_category&amp;lt;T &amp;amp;&amp;gt; {
  static constexpr const char *str() { return "lvalue"; }
};

template &amp;lt;typename T&amp;gt; struct value_category&amp;lt;T &amp;amp;&amp;amp;&amp;gt; {
  static constexpr const char *str() { return "xvalue"; }
};

// Macro to check the value category of an expression
#define PRINT_VALUE_CATEGORY(expr) \
  std::cout &amp;lt;&amp;lt; "The expression '" #expr "' is a " \
            &amp;lt;&amp;lt; value_category&amp;lt;decltype((expr))&amp;gt;::str() &amp;lt;&amp;lt; std::endl;

int main() {
  Widget &amp;amp;&amp;amp;var1 = makeWidget();
  Widget var2 = static_cast&amp;lt;Widget &amp;amp;&amp;amp;&amp;gt;(var1);
  Widget &amp;amp;var4 = var2;

  PRINT_VALUE_CATEGORY(var1); // lvalue
  PRINT_VALUE_CATEGORY(static_cast&amp;lt;Widget &amp;amp;&amp;amp;&amp;gt;(var1)); // xvalue
  PRINT_VALUE_CATEGORY(var4); // lvalue
  PRINT_VALUE_CATEGORY((var4)); // lvalue
  PRINT_VALUE_CATEGORY(std::move(var4)); // xvalue
  PRINT_VALUE_CATEGORY(makeWidget()); // prvalue
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  static_cast vs decltype
&lt;/h1&gt;

&lt;p&gt;Let’s compare &lt;code&gt;static_cast&lt;/code&gt; and &lt;code&gt;decltype&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;static_cast&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As with all cast expressions, the result is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An lvalue if target-type is an lvalue reference type or an rvalue reference to function type(since C++11);&lt;/li&gt;
&lt;li&gt;A xvalue if target-type is an rvalue reference to object type; &lt;a href="https://dev.tosince%20C++11"&gt;swq: how &lt;code&gt;std::move&lt;/code&gt; is implemented&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A prvalue otherwise.(non-reference type)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;With &lt;code&gt;decltype&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;if value category of expression is xvalue, it yields T&amp;amp;&amp;amp;&lt;/li&gt;
&lt;li&gt;if value category of expression is lvalue, it yields T&amp;amp;&lt;/li&gt;
&lt;li&gt;if value category of expression is prvalue, it yields T&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;They do reverse operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;static_cast&lt;/code&gt; sets the type/value category (via the target type).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;decltype&lt;/code&gt; infers the type/value category (from the expression).&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  declval
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://en.cppreference.com/w/cpp/utility/declval" rel="noopener noreferrer"&gt;C++ declval&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;declval&lt;/code&gt; can return a reference to a type, &lt;strong&gt;without going through actual construction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
typename std::add_rvalue_reference&amp;lt;T&amp;gt;::type declval() noexcept
{
    static_assert(false, "declval not allowed in an evaluated context");
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;What &lt;code&gt;declval&lt;/code&gt; does is simply add rvalue reference to type &lt;code&gt;T&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;static_cast&lt;/code&gt; statement make sure that it can only be used in &lt;code&gt;unevaluated&lt;/code&gt; context, like inside &lt;code&gt;decltype&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/20303250/is-there-a-reason-declval-returns-add-rvalue-reference-instead-of-add-lvalue-ref/20303350#20303350" rel="noopener noreferrer"&gt;Why add rvalue reference, instead of lvalue reference?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason is related to reference collapsing rules: only by adding rvalue reference, &lt;code&gt;declval&lt;/code&gt; might have the possibility return a rvalue reference, so as to have more possibility to call methods, such as methods that can only be called by rvalue.&lt;/p&gt;

</description>
      <category>cpp</category>
    </item>
    <item>
      <title>Variable-length shared memory ring buffer</title>
      <dc:creator>weiqiang.shan</dc:creator>
      <pubDate>Sun, 12 Jan 2025 01:22:46 +0000</pubDate>
      <link>https://dev.to/weiqiang/variable-length-shared-memory-ring-buffer-30hi</link>
      <guid>https://dev.to/weiqiang/variable-length-shared-memory-ring-buffer-30hi</guid>
      <description>&lt;p&gt;A variable-length shard memory ring buffer that supports sharing variable length payloads data between processes. This is based on &lt;a href="https://github.com/bo-yang/shm%5C_ring%5C_buffer" rel="noopener noreferrer"&gt;https://github.com/bo-yang/shm\_ring\_buffer&lt;/a&gt;, which only support POD fixed length data. The idea is illustrated in following diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxocfnlx0icxxw488ei2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxocfnlx0icxxw488ei2.png" alt="alt text" width="800" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/shan-weiqiang/shm_ring_buffer" rel="noopener noreferrer"&gt;shm_ring_buffer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>c</category>
    </item>
  </channel>
</rss>
