<!DOCTYPE html>
<html>
<head>
  <meta charset=UTF-8 /><meta name=viewport content="width=device-width, initial-scale=1"/><link rel=preconnent href=https://fonts.googleapis.com />
  <link rel=preconnent href=https://fonts.gstatic.com crossorigin/>
  <link rel=stylesheet href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Noto+Serif:ital,wght@0,100..900;1,100..900&display=swap"/>
  <style>
html {
    --sans-serif-family: "Noto Sans", sans-serif;
    --serif-family: "Noto Serif", serif;
    --monospace-family: "Fira Code", monospace;

    --light-background-color: white;
    --light-deep-background-color: #fafafa;
    --light-text-color: black;
    --light-border-color: #aaa;
    --light-table-border-color: #777;
    --light-del-color: #be1621;
    --light-del-background-color: #fbe6e8;
    --light-ins-color: #17752d;
    --light-ins-background-color: #e4faea;
    --light-para-color: rgb(10, 73, 136);
    --light-a-color: rgb(10, 73, 136);
    --light-a-visited-color: rgb(44, 10, 136);
    --light-a-hover-color: rgb(15, 93, 170);
    --light-mark-color: black;
    --light-mark-background-color: #ffff85;
    --light-abstract-border-color: #707070;
    --light-abstract-background-color: #f0f0f0;
    --light-abstract-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M660-160h40v-160h-40v160Zm20-200q8 0 14-6t6-14q0-8-6-14t-14-6q-8 0-14 6t-6 14q0 8 6 14t14 6ZM200-800v640-640 200-200Zm80 400h147q11-23 25.5-43t32.5-37H280v80Zm0 160h123q-3-20-3-40t3-40H280v80ZM200-80q-33 0-56.5-23.5T120-160v-640q0-33 23.5-56.5T200-880h320l240 240v92q-19-6-39-9t-41-3v-40H480v-200H200v640h227q11 23 25.5 43T485-80H200Zm480-400q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480Z"/></svg>');
    --light-blockquote-border-color: #707070;
    --light-blockquote-background-color: #f0f0f0;
    --light-blockquote-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="%23707070"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M7.17 17c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94zm10 0c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94z"/></svg>');
    --light-bug-block-border-color: #9f7b5d;
    --light-bug-block-background-color: #f0e2d9;
    --light-bug-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%239f7b5d"><path d="M480-120q-64 0-114.5-33T283-240l-95 54-40-69 103-60q-3-11-5-22.5t-4-22.5H120v-80h122q2-12 4-23.5t5-22.5l-103-60 40-69 94 55q8-14 18.5-27.5T322-612q-2-7-2-14v-14q0-24 7-46t19-41l-66-66 56-57 70 68q17-9 35.5-13.5T480-800q20 0 39 5t36 14l69-69 56 57-66 66q12 19 18.5 41t6.5 46v13.5q0 6.5-2 13.5 11 11 21.5 25t18.5 28l95-54 40 69-104 59q3 11 5.5 22.5T718-440h122v80H718q-2 12-4 23.5t-5 22.5l103 60-40 69-95-55q-32 54-82.5 87T480-120Zm-76-546q17-7 36.5-10.5T480-680q20 0 38.5 3t35.5 10q-8-23-28-38t-46-15q-26 0-47 15.5T404-666Zm76 466q73 0 116.5-61T640-400q0-70-40.5-135T480-600q-78 0-119 64.5T320-400q0 78 43.5 139T480-200Zm-40-80v-240h80v240h-80Z"/></svg>');
    --light-decision-block-border-color: #ab6fa2;
    --light-decision-block-background-color: #f4e6f4;
    --light-decision-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab6fa2"><path d="M160-120v-80h480v80H160Zm226-194L160-540l84-86 228 226-86 86Zm254-254L414-796l86-84 226 226-86 86Zm184 408L302-682l56-56 522 522-56 56Z"/></svg>');
    --light-del-block-border-color: #be1621;
    --light-del-block-background-color: #fbe6e8;
    --light-del-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23be1621"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>');
    --light-details-border-color: #707070;
    --light-details-background-color: #f0f0f0;
    --light-details-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --light-diff-block-border-color: #707070;
    --light-diff-block-background-color: #f0f0f0;
    --light-diff-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M500-520h80v-80h80v-80h-80v-80h-80v80h-80v80h80v80Zm-80 160h240v-80H420v80ZM320-200q-33 0-56.5-23.5T240-280v-560q0-33 23.5-56.5T320-920h280l240 240v400q0 33-23.5 56.5T760-200H320Zm0-80h440v-360L560-840H320v560ZM160-40q-33 0-56.5-23.5T80-120v-560h80v560h440v80H160Zm160-240v-560 560Z"/></svg>');
    --light-example-block-border-color: #6f8aab;
    --light-example-block-background-color: #e6e9f4;
    --light-example-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236f8aab"><path d="M300-80q-58 0-99-41t-41-99v-520q0-58 41-99t99-41h500v600q-25 0-42.5 17.5T740-220q0 25 17.5 42.5T800-160v80H300Zm-60-267q14-7 29-10t31-3h20v-440h-20q-25 0-42.5 17.5T240-740v393Zm160-13h320v-440H400v440Zm-160 13v-453 453Zm60 187h373q-6-14-9.5-28.5T660-220q0-16 3-31t10-29H300q-26 0-43 17.5T240-220q0 26 17 43t43 17Z"/></svg>');
    --light-important-block-border-color: #b05252;
    --light-important-block-background-color: #f4e6e6;
    --light-important-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab6f6f"><path d="M480-120q-33 0-56.5-23.5T400-200q0-33 23.5-56.5T480-280q33 0 56.5 23.5T560-200q0 33-23.5 56.5T480-120Zm-80-240v-480h160v480H400Z"/></svg>');
    --light-ins-block-border-color: #17752d;
    --light-ins-block-background-color: #e4faea;
    --light-ins-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%2317752d"><path d="M440-240h80v-120h120v-80H520v-120h-80v120H320v80h120v120ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>');
    --light-note-block-border-color: #6fab6f;
    --light-note-block-background-color: #e6f4e9;
    --light-note-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236fab6f"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --light-tip-block-border-color: #b0a029;
    --light-tip-block-background-color: #f4f4e6;
    --light-tip-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23b0a029"><path d="M480-80q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-200v-80h320v80H320Zm10-120q-69-41-109.5-110T180-580q0-125 87.5-212.5T480-880q125 0 212.5 87.5T780-580q0 81-40.5 150T630-320H330Zm24-80h252q45-32 69.5-79T700-580q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 54 24.5 101t69.5 79Zm126 0Z"/></svg>');
    --light-todo-block-border-color: #6faba0;
    --light-todo-block-background-color: #e6f4f3;
    --light-todo-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236faba0"><path d="M680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80Zm67-105 28-28-75-75v-112h-40v128l87 87Zm-547 65q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v250q-18-13-38-22t-42-16v-212h-80v120H280v-120h-80v560h212q7 22 16 42t22 38H200Zm280-640q17 0 28.5-11.5T520-800q0-17-11.5-28.5T480-840q-17 0-28.5 11.5T440-800q0 17 11.5 28.5T480-760Z"/></svg>');
    --light-warning-block-border-color: #af8141;
    --light-warning-block-background-color: #f4eee6;
    --light-warning-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23af8141"><path d="M109-120q-11 0-20-5.5T75-140q-5-9-5.5-19.5T75-180l370-640q6-10 15.5-15t19.5-5q10 0 19.5 5t15.5 15l370 640q6 10 5.5 20.5T885-140q-5 9-14 14.5t-20 5.5H109Zm69-80h604L480-720 178-200Zm302-40q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm0-120q17 0 28.5-11.5T520-400v-120q0-17-11.5-28.5T480-560q-17 0-28.5 11.5T440-520v120q0 17 11.5 28.5T480-360Zm0-100Z"/></svg>');
    --light-theme-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="black"><path d="M480-360q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Zm0 80q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480q0 83-58.5 141.5T480-280ZM200-440H40v-80h160v80Zm720 0H760v-80h160v80ZM440-760v-160h80v160h-80Zm0 720v-160h80v160h-80ZM256-650l-101-97 57-59 96 100-52 56Zm492 496-97-101 53-55 101 97-57 59Zm-98-550 97-101 59 57-100 96-56-52ZM154-212l101-97 55 53-97 101-59-57Zm326-268Z"/></svg>');

    --dark-background-color: #202020;
    --dark-deep-background-color: #1a1a1a;
    --dark-text-color: #f0f0f0;
    --dark-border-color: #505050;
    --dark-table-border-color: #777;
    --dark-del-background-color: #67060c;
    --dark-del-color: #ffdcd7;
    --dark-ins-background-color: #033a16;
    --dark-ins-color: #aff5b4;
    --dark-para-color: #5bc0ff;
    --dark-a-color: #5bc0ff;
    --dark-a-visited-color: #c6a8ff;
    --dark-a-hover-color: #afd7ff;
    --dark-mark-color: #ededa8;
    --dark-mark-background-color: #525230;
    --dark-abstract-border-color: #999999;
    --dark-abstract-background-color: #2c2c2c;
    --dark-abstract-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23999999"><path d="M660-160h40v-160h-40v160Zm20-200q8 0 14-6t6-14q0-8-6-14t-14-6q-8 0-14 6t-6 14q0 8 6 14t14 6ZM200-800v640-640 200-200Zm80 400h147q11-23 25.5-43t32.5-37H280v80Zm0 160h123q-3-20-3-40t3-40H280v80ZM200-80q-33 0-56.5-23.5T120-160v-640q0-33 23.5-56.5T200-880h320l240 240v92q-19-6-39-9t-41-3v-40H480v-200H200v640h227q11 23 25.5 43T485-80H200Zm480-400q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480Z"/></svg>');
    --dark-blockquote-border-color: #707070;
    --dark-blockquote-background-color: #2c2c2c;
    --dark-blockquote-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="%23707070"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M7.17 17c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94zm10 0c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94z"/></svg>');
    --dark-bug-block-border-color: #ab866f;
    --dark-bug-block-background-color: #373028;
    --dark-bug-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab866f"><path d="M480-120q-64 0-114.5-33T283-240l-95 54-40-69 103-60q-3-11-5-22.5t-4-22.5H120v-80h122q2-12 4-23.5t5-22.5l-103-60 40-69 94 55q8-14 18.5-27.5T322-612q-2-7-2-14v-14q0-24 7-46t19-41l-66-66 56-57 70 68q17-9 35.5-13.5T480-800q20 0 39 5t36 14l69-69 56 57-66 66q12 19 18.5 41t6.5 46v13.5q0 6.5-2 13.5 11 11 21.5 25t18.5 28l95-54 40 69-104 59q3 11 5.5 22.5T718-440h122v80H718q-2 12-4 23.5t-5 22.5l103 60-40 69-95-55q-32 54-82.5 87T480-120Zm-76-546q17-7 36.5-10.5T480-680q20 0 38.5 3t35.5 10q-8-23-28-38t-46-15q-26 0-47 15.5T404-666Zm76 466q73 0 116.5-61T640-400q0-70-40.5-135T480-600q-78 0-119 64.5T320-400q0 78 43.5 139T480-200Zm-40-80v-240h80v240h-80Z"/></svg>');
    --dark-details-border-color: #707070;
    --dark-details-background-color: #2c2c2c;
    --dark-details-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --dark-decision-block-border-color: #ab6fa2;
    --dark-decision-block-background-color: #30232d;
    --dark-decision-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab6fa2"><path d="M160-120v-80h480v80H160Zm226-194L160-540l84-86 228 226-86 86Zm254-254L414-796l86-84 226 226-86 86Zm184 408L302-682l56-56 522 522-56 56Z"/></svg>');
    --dark-del-block-border-color: #be5e64;
    --dark-del-block-background-color: #302323;
    --dark-del-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23be5e64"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>');
    --dark-diff-block-border-color: #707070;
    --dark-diff-block-background-color: #2c2c2c;
    --dark-diff-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M500-520h80v-80h80v-80h-80v-80h-80v80h-80v80h80v80Zm-80 160h240v-80H420v80ZM320-200q-33 0-56.5-23.5T240-280v-560q0-33 23.5-56.5T320-920h280l240 240v400q0 33-23.5 56.5T760-200H320Zm0-80h440v-360L560-840H320v560ZM160-40q-33 0-56.5-23.5T80-120v-560h80v560h440v80H160Zm160-240v-560 560Z"/></svg>');
    --dark-example-block-border-color: #6f81ab;
    --dark-example-block-background-color: #232630;
    --dark-example-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236f81ab"><path d="M300-80q-58 0-99-41t-41-99v-520q0-58 41-99t99-41h500v600q-25 0-42.5 17.5T740-220q0 25 17.5 42.5T800-160v80H300Zm-60-267q14-7 29-10t31-3h20v-440h-20q-25 0-42.5 17.5T240-740v393Zm160-13h320v-440H400v440Zm-160 13v-453 453Zm60 187h373q-6-14-9.5-28.5T660-220q0-16 3-31t10-29H300q-26 0-43 17.5T240-220q0 26 17 43t43 17Z"/></svg>');
    --dark-important-block-border-color: #b06262;
    --dark-important-block-background-color: #302323;
    --dark-important-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23b06262"><path d="M480-120q-33 0-56.5-23.5T400-200q0-33 23.5-56.5T480-280q33 0 56.5 23.5T560-200q0 33-23.5 56.5T480-120Zm-80-240v-480h160v480H400Z"/></svg>');
    --dark-ins-block-border-color: #5bab6d;
    --dark-ins-block-background-color: #233023;
    --dark-ins-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%235bab6d"><path d="M440-240h80v-120h120v-80H520v-120h-80v120H320v80h120v120ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>');
    --dark-note-block-border-color: #6fab76;
    --dark-note-block-background-color: #233025;
    --dark-note-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236fab76"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --dark-tip-block-border-color: #a2ab6f;
    --dark-tip-block-background-color: #2f3023;
    --dark-tip-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23a2ab6f"><path d="M480-80q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-200v-80h320v80H320Zm10-120q-69-41-109.5-110T180-580q0-125 87.5-212.5T480-880q125 0 212.5 87.5T780-580q0 81-40.5 150T630-320H330Zm24-80h252q45-32 69.5-79T700-580q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 54 24.5 101t69.5 79Zm126 0Z"/></svg>');
    --dark-todo-block-border-color: #6fab98;
    --dark-todo-block-background-color: #23302e;
    --dark-todo-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236fab98"><path d="M680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80Zm67-105 28-28-75-75v-112h-40v128l87 87Zm-547 65q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v250q-18-13-38-22t-42-16v-212h-80v120H280v-120h-80v560h212q7 22 16 42t22 38H200Zm280-640q17 0 28.5-11.5T520-800q0-17-11.5-28.5T480-840q-17 0-28.5 11.5T440-800q0 17 11.5 28.5T480-760Z"/></svg>');
    --dark-warning-block-border-color: #ab9c6f;
    --dark-warning-block-background-color: #302b23;
    --dark-warning-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab9c6f"><path d="M109-120q-11 0-20-5.5T75-140q-5-9-5.5-19.5T75-180l370-640q6-10 15.5-15t19.5-5q10 0 19.5 5t15.5 15l370 640q6 10 5.5 20.5T885-140q-5 9-14 14.5t-20 5.5H109Zm69-80h604L480-720 178-200Zm302-40q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm0-120q17 0 28.5-11.5T520-400v-120q0-17-11.5-28.5T480-560q-17 0-28.5 11.5T440-520v120q0 17 11.5 28.5T480-360Zm0-100Z"/></svg>');
    --dark-theme-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23f0f0f0"><path d="M480-120q-150 0-255-105T120-480q0-150 105-255t255-105q14 0 27.5 1t26.5 3q-41 29-65.5 75.5T444-660q0 90 63 153t153 63q55 0 101-24.5t75-65.5q2 13 3 26.5t1 27.5q0 150-105 255T480-120Zm0-80q88 0 158-48.5T740-375q-20 5-40 8t-40 3q-123 0-209.5-86.5T364-660q0-20 3-40t8-40q-78 32-126.5 102T200-480q0 116 82 198t198 82Zm-10-270Z"/></svg>');

    --indent: 2.5em;
    --border-radius: 0.25em;
}

/* BEGIN LIGHT AND DARK THEME */

@media (prefers-color-scheme: light) {
    html {
        --background-color: var(--light-background-color);
        --deep-background-color: var(--light-deep-background-color);
        --text-color: var(--light-text-color);
        --border-color: var(--light-border-color);
        --table-border-color: var(--light-table-border-color);
        --del-color: var(--light-del-color);
        --del-background-color: var(--light-del-background-color);
        --ins-color: var(--light-ins-color);
        --ins-background-color: var(--light-ins-background-color);
        --para-color: var(--light-para-color);
        --a-color: var(--light-a-color);
        --a-visited-color: var(--light-a-visited-color);
        --a-hover-color: var(--light-a-hover-color);
        --mark-color: var(--light-mark-color);
        --mark-background-color: var(--light-mark-background-color);
        --abstract-border-color: var(--light-abstract-border-color);
        --abstract-background-color: var(--light-abstract-background-color);
        --abstract-image: var(--light-abstract-image);
        --blockquote-border-color: var(--light-blockquote-border-color);
        --blockquote-background-color: var(--light-blockquote-background-color);
        --blockquote-image: var(--light-blockquote-image);
        --bug-block-border-color: var(--light-bug-block-border-color);
        --bug-block-background-color: var(--light-bug-block-background-color);
        --bug-block-image: var(--light-bug-block-image);
        --decision-block-border-color: var(--light-decision-block-border-color);
        --decision-block-background-color: var(--light-decision-block-background-color);
        --decision-block-image: var(--light-decision-block-image);
        --del-block-border-color: var(--light-del-block-border-color);
        --del-block-background-color: var(--light-del-block-background-color);
        --del-block-image: var(--light-del-block-image);
        --details-border-color: var(--light-details-border-color);
        --details-background-color: var(--light-details-background-color);
        --details-image: var(--light-details-image);
        --diff-block-border-color: var(--light-diff-block-border-color);
        --diff-block-background-color: var(--light-diff-block-background-color);
        --diff-block-image: var(--light-diff-block-image);
        --example-block-border-color: var(--light-example-block-border-color);
        --example-block-background-color: var(--light-example-block-background-color);
        --example-block-image: var(--light-example-block-image);
        --important-block-border-color: var(--light-important-block-border-color);
        --important-block-background-color: var(--light-important-block-background-color);
        --important-block-image: var(--light-important-block-image);
        --ins-block-border-color: var(--light-ins-block-border-color);
        --ins-block-background-color: var(--light-ins-block-background-color);
        --ins-block-image: var(--light-ins-block-image);
        --note-block-border-color: var(--light-note-block-border-color);
        --note-block-background-color: var(--light-note-block-background-color);
        --note-block-image: var(--light-note-block-image);
        --tip-block-border-color: var(--light-tip-block-border-color);
        --tip-block-background-color: var(--light-tip-block-background-color);
        --tip-block-image: var(--light-tip-block-image);
        --todo-block-border-color: var(--light-todo-block-border-color);
        --todo-block-background-color: var(--light-todo-block-background-color);
        --todo-block-image: var(--light-todo-block-image);
        --warning-block-border-color: var(--light-warning-block-border-color);
        --warning-block-background-color: var(--light-warning-block-background-color);
        --warning-block-image: var(--light-warning-block-image);
        --theme-icon: var(--light-theme-icon);
    }
}

@media (prefers-color-scheme: dark) {
    html {
        --background-color: var(--dark-background-color);
        --deep-background-color: var(--dark-deep-background-color);
        --text-color: var(--dark-text-color);
        --border-color: var(--dark-border-color);
        --table-border-color: var(--dark-table-border-color);
        --del-color: var(--dark-del-color);
        --del-background-color: var(--dark-del-background-color);
        --ins-color: var(--dark-ins-color);
        --ins-background-color: var(--dark-ins-background-color);
        --para-color: var(--dark-para-color);
        --a-color: var(--dark-a-color);
        --a-visited-color: var(--dark-a-visited-color);
        --a-hover-color: var(--dark-a-hover-color);
        --mark-color: var(--dark-mark-color);
        --mark-background-color: var(--dark-mark-background-color);
        --abstract-border-color: var(--dark-abstract-border-color);
        --abstract-background-color: var(--dark-abstract-background-color);
        --abstract-image: var(--dark-abstract-image);
        --blockquote-border-color: var(--dark-blockquote-border-color);
        --blockquote-background-color: var(--dark-blockquote-background-color);
        --blockquote-image: var(--dark-blockquote-image);
        --bug-block-border-color: var(--dark-bug-block-border-color);
        --bug-block-background-color: var(--dark-bug-block-background-color);
        --bug-block-image: var(--dark-bug-block-image);
        --decision-block-border-color: var(--dark-decision-block-border-color);
        --decision-block-background-color: var(--dark-decision-block-background-color);
        --decision-block-image: var(--dark-decision-block-image);
        --del-block-border-color: var(--dark-del-block-border-color);
        --del-block-background-color: var(--dark-del-block-background-color);
        --del-block-image: var(--dark-del-block-image);
        --details-border-color: var(--dark-details-border-color);
        --details-background-color: var(--dark-details-background-color);
        --details-image: var(--dark-details-image);
        --diff-block-border-color: var(--dark-diff-block-border-color);
        --diff-block-background-color: var(--dark-diff-block-background-color);
        --diff-block-image: var(--dark-diff-block-image);
        --example-block-border-color: var(--dark-example-block-border-color);
        --example-block-background-color: var(--dark-example-block-background-color);
        --example-block-image: var(--dark-example-block-image);
        --important-block-border-color: var(--dark-important-block-border-color);
        --important-block-background-color: var(--dark-important-block-background-color);
        --important-block-image: var(--dark-important-block-image);
        --ins-block-border-color: var(--dark-ins-block-border-color);
        --ins-block-background-color: var(--dark-ins-block-background-color);
        --ins-block-image: var(--dark-ins-block-image);
        --note-block-border-color: var(--dark-note-block-border-color);
        --note-block-background-color: var(--dark-note-block-background-color);
        --note-block-image: var(--dark-note-block-image);
        --tip-block-border-color: var(--dark-tip-block-border-color);
        --tip-block-background-color: var(--dark-tip-block-background-color);
        --tip-block-image: var(--dark-tip-block-image);
        --todo-block-border-color: var(--dark-todo-block-border-color);
        --todo-block-background-color: var(--dark-todo-block-background-color);
        --todo-block-image: var(--dark-todo-block-image);
        --warning-block-border-color: var(--dark-warning-block-border-color);
        --warning-block-background-color: var(--dark-warning-block-background-color);
        --warning-block-image: var(--dark-warning-block-image);
        --theme-icon: var(--dark-theme-icon);
    }
}

html.light {
    --background-color: var(--light-background-color);
    --deep-background-color: var(--light-deep-background-color);
    --text-color: var(--light-text-color);
    --border-color: var(--light-border-color);
    --table-border-color: var(--light-table-border-color);
    --del-color: var(--light-del-color);
    --del-background-color: var(--light-del-background-color);
    --ins-color: var(--light-ins-color);
    --ins-background-color: var(--light-ins-background-color);
    --para-color: var(--light-para-color);
    --a-color: var(--light-a-color);
    --a-visited-color: var(--light-a-visited-color);
    --a-hover-color: var(--light-a-hover-color);
    --mark-color: var(--light-mark-color);
    --mark-background-color: var(--light-mark-background-color);
    --abstract-border-color: var(--light-abstract-border-color);
    --abstract-background-color: var(--light-abstract-background-color);
    --abstract-image: var(--light-abstract-image);
    --blockquote-border-color: var(--light-blockquote-border-color);
    --blockquote-background-color: var(--light-blockquote-background-color);
    --blockquote-image: var(--light-blockquote-image);
    --bug-block-border-color: var(--light-bug-block-border-color);
    --bug-block-background-color: var(--light-bug-block-background-color);
    --bug-block-image: var(--light-bug-block-image);
    --decision-block-border-color: var(--light-decision-block-border-color);
    --decision-block-background-color: var(--light-decision-block-background-color);
    --decision-block-image: var(--light-decision-block-image);
    --del-block-border-color: var(--light-del-block-border-color);
    --del-block-background-color: var(--light-del-block-background-color);
    --del-block-image: var(--light-del-block-image);
    --details-border-color: var(--light-details-border-color);
    --details-background-color: var(--light-details-background-color);
    --details-image: var(--light-details-image);
    --diff-block-border-color: var(--light-diff-block-border-color);
    --diff-block-background-color: var(--light-diff-block-background-color);
    --diff-block-image: var(--light-diff-block-image);
    --example-block-border-color: var(--light-example-block-border-color);
    --example-block-background-color: var(--light-example-block-background-color);
    --example-block-image: var(--light-example-block-image);
    --important-block-border-color: var(--light-important-block-border-color);
    --important-block-background-color: var(--light-important-block-background-color);
    --important-block-image: var(--light-important-block-image);
    --ins-block-border-color: var(--light-ins-block-border-color);
    --ins-block-background-color: var(--light-ins-block-background-color);
    --ins-block-image: var(--light-ins-block-image);
    --note-block-border-color: var(--light-note-block-border-color);
    --note-block-background-color: var(--light-note-block-background-color);
    --note-block-image: var(--light-note-block-image);
    --tip-block-border-color: var(--light-tip-block-border-color);
    --tip-block-background-color: var(--light-tip-block-background-color);
    --tip-block-image: var(--light-tip-block-image);
    --todo-block-border-color: var(--light-todo-block-border-color);
    --todo-block-background-color: var(--light-todo-block-background-color);
    --todo-block-image: var(--light-todo-block-image);
    --warning-block-border-color: var(--light-warning-block-border-color);
    --warning-block-background-color: var(--light-warning-block-background-color);
    --warning-block-image: var(--light-warning-block-image);
    --theme-icon: var(--light-theme-icon);
}

html.dark {
    --background-color: var(--dark-background-color);
    --deep-background-color: var(--dark-deep-background-color);
    --text-color: var(--dark-text-color);
    --border-color: var(--dark-border-color);
    --table-border-color: var(--dark-table-border-color);
    --del-color: var(--dark-del-color);
    --del-background-color: var(--dark-del-background-color);
    --ins-color: var(--dark-ins-color);
    --ins-background-color: var(--dark-ins-background-color);
    --para-color: var(--dark-para-color);
    --a-color: var(--dark-a-color);
    --a-visited-color: var(--dark-a-visited-color);
    --a-hover-color: var(--dark-a-hover-color);
    --mark-color: var(--dark-mark-color);
    --mark-background-color: var(--dark-mark-background-color);
    --abstract-border-color: var(--dark-abstract-border-color);
    --abstract-background-color: var(--dark-abstract-background-color);
    --abstract-image: var(--dark-abstract-image);
    --blockquote-border-color: var(--dark-blockquote-border-color);
    --blockquote-background-color: var(--dark-blockquote-background-color);
    --blockquote-image: var(--dark-blockquote-image);
    --bug-block-border-color: var(--dark-bug-block-border-color);
    --bug-block-background-color: var(--dark-bug-block-background-color);
    --bug-block-image: var(--dark-bug-block-image);
    --decision-block-border-color: var(--dark-decision-block-border-color);
    --decision-block-background-color: var(--dark-decision-block-background-color);
    --decision-block-image: var(--dark-decision-block-image);
    --del-block-border-color: var(--dark-del-block-border-color);
    --del-block-background-color: var(--dark-del-block-background-color);
    --del-block-image: var(--dark-del-block-image);
    --details-border-color: var(--dark-details-border-color);
    --details-background-color: var(--dark-details-background-color);
    --details-image: var(--dark-details-image);
    --diff-block-border-color: var(--dark-diff-block-border-color);
    --diff-block-background-color: var(--dark-diff-block-background-color);
    --diff-block-image: var(--dark-diff-block-image);
    --example-block-border-color: var(--dark-example-block-border-color);
    --example-block-background-color: var(--dark-example-block-background-color);
    --example-block-image: var(--dark-example-block-image);
    --important-block-border-color: var(--dark-important-block-border-color);
    --important-block-background-color: var(--dark-important-block-background-color);
    --important-block-image: var(--dark-important-block-image);
    --ins-block-border-color: var(--dark-ins-block-border-color);
    --ins-block-background-color: var(--dark-ins-block-background-color);
    --ins-block-image: var(--dark-ins-block-image);
    --note-block-border-color: var(--dark-note-block-border-color);
    --note-block-background-color: var(--dark-note-block-background-color);
    --note-block-image: var(--dark-note-block-image);
    --tip-block-border-color: var(--dark-tip-block-border-color);
    --tip-block-background-color: var(--dark-tip-block-background-color);
    --tip-block-image: var(--dark-tip-block-image);
    --todo-block-border-color: var(--dark-todo-block-border-color);
    --todo-block-background-color: var(--dark-todo-block-background-color);
    --todo-block-image: var(--dark-todo-block-image);
    --warning-block-border-color: var(--dark-warning-block-border-color);
    --warning-block-background-color: var(--dark-warning-block-background-color);
    --warning-block-image: var(--dark-warning-block-image);
    --theme-icon: var(--dark-theme-icon);
}

/* END LIGHT AND DARK THEME */

html {
    margin: 0;
    width: 100%;
    font-family: var(--serif-family);
    font-size: 11pt;

    border-left: var(--border-thickness) solid var(--border-color);
    color: var(--text-color);
    background-color: var(--background-color);
}

body {
    --vertical-margin: 2rem;
    --margin-left: 3rem;
    --margin-right: 2rem;

    margin: var(--vertical-margin) var(--margin-right) var(--vertical-margin) var(--margin-left);
    width: calc(100% - var(--margin-left) - var(--margin-right));
    box-sizing: border-box;
}

main {
    max-width: 60rem;
    margin-left: auto;
    margin-right: auto;
}

p {
    text-align: justify;
}

abstract-block,
blockquote,
bug-block,
code-block,
decision-block,
del-block,
details,
dl,
diff-block,
example-block,
hr,
ol,
important-block,
ins-block,
math[display=block],
note-block,
p,
pre,
tip-block,
todo-block,
ul,
warning-block,
.indent {
    display: block;
    margin-top: 1em;
    margin-bottom: 1em;
}

a {
    color: var(--a-color);
    text-decoration: unset;
}

a:visited {
    color: var(--a-visited-color);
}

a:hover,
a:focus {
    color: var(--a-hover-color);
}

a:hover {
    text-decoration: underline;
}

ol,
ul {
    padding-left: var(--indent);
}

li {
    margin: 0.5em 0;
}

dt {
    margin-top: 0.25em;
    font-style: italic;
    font-weight: bold;
}

dd {
    margin-bottom: 0.25em;
    margin-left: var(--indent);
}

abstract-block,
blockquote,
bug-block,
del-block,
details,
decision-block,
diff-block,
example-block,
important-block,
ins-block,
note-block,
tip-block,
todo-block,
warning-block {
    --border-thickness: 0.25em;
    --padding: 0.5em;

    position: relative;
    width: calc(100% - var(--indent));
    box-sizing: border-box;
    padding: var(--padding);
    margin-left: var(--indent);

    border-top-right-radius: var(--border-radius);
    border-bottom-right-radius: var(--border-radius);
}

abstract-block>:first-child,
blockquote>:first-child,
bug-block>:first-child,
del-block>:first-child,
details>:first-child,
decision-block>:first-child,
diff-block>:first-child,
example-block>:first-child,
important-block>:first-child,
ins-block>:first-child,
note-block>:first-child,
tip-block>:first-child,
todo-block>:first-child,
warning-block>:first-child {
    margin-top: 0;
}

abstract-block>:last-child,
blockquote>:last-child,
bug-block>:last-child,
del-block>:last-child,
details>:last-child,
decision-block>:last-child,
diff-block>:last-child,
example-block>:last-child,
important-block>:last-child,
ins-block>:last-child,
note-block>:last-child,
todo-block>:last-child,
tip-block>:last-child,
warning-block>:last-child {
    margin-bottom: 0;
}

abstract-block::before,
blockquote::before,
bug-block::before,
del-block::before,
details::before,
decision-block::before,
diff-block::before,
example-block::before,
important-block::before,
ins-block::before,
note-block::before,
todo-block::before,
tip-block::before,
warning-block::before {
    position: absolute;
    left: -2.5em;
    top: 0.25em;
    width: 2em;
    height: 2em;

    content: "";
    display: inline-block;
    background-size: contain;
    background-repeat: no-repeat;

}

code,
code-block,
pre,
samp,
tt,
tt-,
.mono {
    font-family: var(--monospace-family);
    font-style: normal;
    font-variant-ligatures: none;
}

code-block:not(.borderless),
pre {
    padding: 0.5em;
    border-radius: var(--border-radius);
    box-sizing: border-box;

    background-color: var(--deep-background-color);
    border: 1px solid var(--border-color);
}

code-block,
pre {
    font-size: 95%;
    width: 100%;
}

code-block,
pre {
    white-space: pre;
    overflow-x: auto;
}

/* INSERTIONS AND DELETIONS */

ins,
ins-lines {
    text-decoration: underline;
    font-weight: 600;
    color: var(--ins-color);
    background-color: var(--ins-background-color);
}

code-block ins,
code-block ins-lines {
    text-decoration: inherit;
}

del {
    text-decoration: line-through;
}

del,
del-lines {
    color: var(--del-color);
    background-color: var(--del-background-color);
}

ins-lines,
del-lines {
    display: inline-block;
    width: 100%;
}

ins h-,
ins-lines h-,
del h-,
del-lines h- {
    color: inherit !important;
    background-color: inherit !important;
}

kbd {
    font-family: var(--sans-serif-family);

    display: inline-block;
    padding: 0 0.25em 0.15em 0.25em;
    border-radius: 0.25em;
    white-space: nowrap;

    background-color: var(--deep-background-color);
    border: 1px solid var(--border-color);
    box-shadow: inset 0 -0.1em 0 var(--border-color);
}

mark {
    color: var(--mark-color);
    background-color: var(--mark-background-color);
}

math:not([display=block]) {
    font-size: 120%;
}

math[display=block] {
    width: fit-content;
    margin-left: var(--indent);

    font-size: 110%;
}

g-term,
f-sans,
f-serif,
wg21-block {
    display: inline;
}

f-sans,
.sans {
    font-family: var(--sans-serif-family);
}

f-serif,
.serif {
    font-family: var(--serif-family);
}

.grammar dd,
g-term {
    font-family: var(--sans-serif-family);
    font-style: oblique;
}

.grammar {
    margin-left: var(--indent);
}

.grammar dt {
    font-weight: normal;
    font-style: normal;
}

.oblique {
    font-style: oblique;
}

.word {
    white-space: nowrap;
}

.wg21-head {
    margin-bottom: 4em;
}

.wg21-head dl {
    font-family: var(--sans-serif-family);
}

.wg21-head dt {
    font-style: normal;
}

/* HEADINGS */

h1,
h2,
h3,
h4,
h5,
h6 {
    position: relative;
    margin: 1rem 0;
}

h1 {
    margin: 2rem 0 1.5rem 0;
    font-size: 250%;
}

h2 {
    margin: 2.5rem 0 1.5rem 0;
    font-size: 166%;
}

h3 {
    margin: 2rem 0 1rem 0;
    font-size: 133%;
}

h4 {
    margin: 1.5rem 0 0.5rem 0;
    font-size: 100%;
}

h5 {
    margin: 1rem 0 0.5rem 0;
    font-size: 100%;
    font-weight: normal;
}

h6 {
    margin: 1rem 0 0.5rem 0;
    font-size: 90%;
    font-weight: normal;
}

table {
    --border: 1px solid var(--table-border-color);

    margin-top: 1em;
    margin-bottom: 1em;
    border-collapse: collapse;
}

table,
tbody,
thead,
th {
    border: var(--border);
}

td {
    border-left: var(--border);
    border-right: var(--border);
}

td,
th {
    padding: 0.1em 0.5em;
}

.para {
    cursor: pointer;
    font-weight: normal;
    font-family: var(--monospace-family);
    text-decoration: none;
    opacity: 0.25;

    position: absolute;
    top: 0.05em;
    left: calc(-1rem - 0.5ch);
}

.para,
.para::before {
    color: var(--para-color);
}

.para:hover,
.para:focus,
:target .para {
    opacity: 1;
}

.para::before {
    content: "§";
}

/* TABLE OF CONTENTS */

.toc {
    --h-indent: 0.75em;

    display: grid;
    grid-template-columns: min-content auto;
}

.toc-num {
    display: inline-block;
    align-self: end;
    padding-right: 3em;

    letter-spacing: 0em;
}

.toc h1,
.toc h2,
.toc h3,
.toc h4,
.toc h5,
.toc h6 {
    display: inline-block;

    font-weight: 500;
    font-size: 12pt;

    margin-top: 0;
    margin-bottom: 0;
}

.toc a,
.toc-num {
    border-bottom: 1px solid rgba(0, 0, 0, 0);
    color: var(--text-color);
}

.toc h1,
.toc-num[data-level="1"] {
    font-size: 125%;
    font-weight: 900;
}

.toc h2,
.toc-num[data-level="2"] {
    font-weight: 700;
}

.toc h3,
.toc-num[data-level="3"] {
    font-weight: 500;
}

.toc h4,
.toc-num[data-level="4"] {
    font-size: 95%;
    font-weight: 400;
}

.toc h5,
.toc-num[data-level="5"] {
    font-size: 90%;
    font-weight: 300;
}

.toc h6,
.toc-num[data-level="6"] {
    font-size: 90%;
    font-weight: 100;
}

.toc a:hover {
    display: inline-block;
    width: 100%;

    color: var(--a-hover-color);
    border-bottom: 1px dashed var(--a-hover-color);
}

.toc h1:not(:nth-child(2)>h1) {
    margin-top: 1.5em;
}

.toc h2:not(:nth-child(2)>h2) {
    margin-top: 0.75em;
}

/** BIBLIOGRAPHY */

.bib {
    display: block;
    margin: 1em 0;
}

.bib-item {
    display: inline-block;
    width: 100%;
    margin: 0.25em 0;
}

.bib-item>* {
    padding: 0 0.125em;
}

.bib-author {
    font-style: italic;
}

.bib-title {
    font-weight: 500;
}

.bib-date {
    font-family: var(--monospace-family);
}

.bib-date::before {
    font-family: var(--serif-family);
    content: "(";
}

.bib-date::after {
    font-family: var(--serif-family);
    content: ")";
}

.bib-link {
    display: block;
    margin-left: var(--indent);

    font-family: var(--sans-serif-family);
    font-style: normal;
}

/* SPECIAL BLOCKS */

intro- {
    display: inline-block;

    font-weight: 600;
    text-transform: uppercase;
    font-family: var(--sans-serif-family);
}

abstract-block {
    background-color: var(--abstract-background-color);
    border-left: var(--border-thickness) solid var(--abstract-border-color);
}

abstract-block::before {
    background-image: var(--abstract-image);
}

abstract-block intro-::before {
    content: "Abstract:";
    color: var(--abstract-border-color);
}

blockquote {
    background-color: var(--blockquote-background-color);
    border-left: var(--border-thickness) solid var(--blockquote-border-color);
}

blockquote::before {
    background-image: var(--blockquote-image);
    top: -0.25em;
}

blockquote intro-::before {
    content: "Quote:";
    color: var(--blockquote-border-color);
}

bug-block {
    background-color: var(--bug-block-background-color);
    border-left: var(--border-thickness) solid var(--bug-block-border-color);
}

bug-block::before {
    background-image: var(--bug-block-image);
}

bug-block intro-::before {
    content: "Bug:";
    color: var(--bug-block-border-color);
}

del-block {
    background-color: var(--del-block-background-color);
    border-left: var(--border-thickness) solid var(--del-block-border-color);
    color: var(--del-color);
}

del-block::before {
    background-image: var(--del-block-image);
}

del-block intro-::before {
    content: "Deleted:";
    color: var(--del-block-border-color);
}

del-block code,
del-block code-block {
    color: var(--text-color);
}

details {
    background-color: var(--details-background-color);
    border-left: var(--border-thickness) solid var(--details-border-color);
}

details::before {
    background-image: var(--details-image);
}

summary {
    font-family: var(--sans-serif-family);
    color: var(--details-border-color);
    user-select: none;
    cursor: pointer;
}

details[open]>summary {
    margin-bottom: 0.5em;
}

decision-block {
    background-color: var(--decision-block-background-color);
    border-left: var(--border-thickness) solid var(--decision-block-border-color);
}

decision-block::before {
    background-image: var(--decision-block-image);
}

decision-block intro-::before {
    content: "Decision:";
    color: var(--decision-block-border-color);
}

diff-block {
    background-color: var(--diff-block-background-color);
    border-left: var(--border-thickness) solid var(--diff-block-border-color);
}

diff-block::before {
    background-image: var(--diff-block-image);
}

diff-block intro-::before {
    content: "Difference:";
    color: var(--diff-block-border-color);
}

example-block {
    background-color: var(--example-block-background-color);
    border-left: var(--border-thickness) solid var(--example-block-border-color);
}

example-block::before {
    background-image: var(--example-block-image);
}

example-block intro-::before {
    content: "Example:";
    color: var(--example-block-border-color);
}

important-block {
    background-color: var(--important-block-background-color);
    border-left: var(--border-thickness) solid var(--important-block-border-color);
}

important-block::before {
    background-image: var(--important-block-image);
}

important-block intro-::before {
    content: "Important:";
    color: var(--important-block-border-color);
}

ins-block {
    background-color: var(--ins-block-background-color);
    border-left: var(--border-thickness) solid var(--ins-block-border-color);
    color: var(--ins-color);
}

ins-block code,
ins-block code-block {
    color: var(--text-color);
}

ins-block::before {
    background-image: var(--ins-block-image);
}

ins-block intro-::before {
    content: "Inserted:";
    color: var(--ins-block-border-color);
}

note-block {
    background-color: var(--note-block-background-color);
    border-left: var(--border-thickness) solid var(--note-block-border-color);
}

note-block::before {
    background-image: var(--note-block-image);
}

note-block intro-::before {
    content: "Note:";
    color: var(--note-block-border-color);
}

tip-block {
    background-color: var(--tip-block-background-color);
    border-left: var(--border-thickness) solid var(--tip-block-border-color);
}

tip-block::before {
    background-image: var(--tip-block-image);
}

tip-block intro-::before {
    content: "Tip:";
    color: var(--tip-block-border-color);
}

todo-block {
    background-color: var(--todo-block-background-color);
    border-left: var(--border-thickness) solid var(--todo-block-border-color);
}

todo-block::before {
    background-image: var(--todo-block-image);
}

todo-block intro-::before {
    content: "Todo:";
    color: var(--todo-block-border-color);
}

warning-block {
    background-color: var(--warning-block-background-color);
    border-left: var(--border-thickness) solid var(--warning-block-border-color);
}

warning-block::before {
    background-image: var(--warning-block-image);
}

warning-block intro-::before {
    content: "Warning:";
    color: var(--warning-block-border-color);
}

.indent {
    margin-left: var(--indent);
}

/* SETTINGS MENU */

#settings:not(.js) {
    display: none;
}

#settings {
    z-index: 999;
    position: fixed;
    display: inline-block;
    top: 1em;
    right: 1em;
}

#theme-icon {
    display: block;
    width: 2.5em;
    height: 2.5em;
    cursor: pointer;
    background-image: var(--theme-icon);
    background-size: contain;
    opacity: 0.25;
}

#theme-icon:hover,
#theme-icon:focus {
    opacity: 1;
}
  </style>
  <style>
@media (prefers-color-scheme: light) {
h-[data-h^=err] { color:#ff0000; }
h-[data-h^=cmt] { color:green; font-style:italic; }
h-[data-h^=cmt_dlim] { font-style:normal; }
h-[data-h^=val] { color:#9f6807; }
h-[data-h^=num] { color:#9f6807; }
h-[data-h^=str] { color:#9f6807; }
h-[data-h^=esc] { color:#9f6807; }
h-[data-h^=null] { color:#00607c; }
h-[data-h^=bool] { color:#9f6807; }
h-[data-h^=this] { color:#00607c; }
h-[data-h^=mac] { color:#6f4e37; }
h-[data-h^=id] { color:#000000; }
h-[data-h^=id_labl] { color:#517a0b; }
h-[data-h^=id_nt] { font-style:italic; }
h-[data-h^=id_nt_dcl] { color:#00607c; font-style:italic; }
h-[data-h^=kw] { color:#00607c; }
h-[data-h^=sym] { color:#570057; }
h-[data-h^=sym_punc] { color:#000000; }
h-[data-h^=sym_par] { color:#af1915; }
h-[data-h^=sym_sqr] { color:#af1915; }
h-[data-h^=sym_brac] { color:#af1915; }
h-[data-h^=diff_head] { color:#777777; }
h-[data-h^=diff_head_hunk] { color:#5c477e; }
h-[data-h^=diff_eq] { color:#000000; }
h-[data-h^=diff_del] { color:#b31d28; background-color:#ffeef0; }
h-[data-h^=diff_ins] { color:#22863a; background-color:#f0fff4; }
h-[data-h^=diff_mod] { color:#7a680d; background-color:#fffdee; }
h-[data-h^=mk_tag] { color:#00607c; }
h-[data-h^=mk_attr] { color:#5c477e; }
h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
h-[data-h^=mk_emph] { font-style:italic; }
h-[data-h^=mk_stro] { font-weight:bold; }
h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
h-[data-h^=mk_ulin] { text-decoration:underline; }
h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
h-[data-h^=mk_strk] { text-decoration:line-through; }
h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
h-[data-h^=sh_cmd] { color:#00607c; }
h-[data-h^=sh-opt] { color:#000000; }
h-[data-h^=asm_ins] { color:#00607c; }
h-[data-h^=asm_ins_psu] { color:#9f6807; }
}
@media (prefers-color-scheme: dark) {
h-[data-h^=err] { color:#ff0000; }
h-[data-h^=cmt] { color:#a2e08d; font-style:italic; }
h-[data-h^=cmt_dlim] { font-style:normal; }
h-[data-h^=val] { color:#f2d18d; }
h-[data-h^=num] { color:#f2d18d; }
h-[data-h^=num_dlim] { color:#e6b191; }
h-[data-h^=num_deco] { color:#e6b191; }
h-[data-h^=str] { color:#f2d18d; }
h-[data-h^=str_dlim] { color:#e6b191; }
h-[data-h^=str_deco] { color:#e6b191; }
h-[data-h^=esc] { color:#e6aee6; }
h-[data-h^=null] { color:#62ded6; }
h-[data-h^=bool] { color:#f2d18d; }
h-[data-h^=this] { color:#62ded6; }
h-[data-h^=mac] { color:#cc946e; }
h-[data-h^=id] { color:#f0f0f0; }
h-[data-h^=id_labl] { color:#d8eda6; }
h-[data-h^=id_nt] { font-style:italic; }
h-[data-h^=id_nt_dcl] { color:#62ded6; font-style:italic; }
h-[data-h^=kw] { color:#62ded6; }
h-[data-h^=sym] { color:#baa6b9; }
h-[data-h^=sym_punc] { color:#d0d0d0; }
h-[data-h^=sym_par] { color:#fa7878; }
h-[data-h^=sym_sqr] { color:#fa7878; }
h-[data-h^=sym_brac] { color:#fa7878; }
h-[data-h^=diff_head] { color:#777777; }
h-[data-h^=diff_head_hunk] { color:#edc385; }
h-[data-h^=diff_eq] { color:#e7e7e7; }
h-[data-h^=diff_del] { color:#ffdcd7; background-color:#67060c; }
h-[data-h^=diff_ins] { color:#aff5b4; background-color:#033a16; }
h-[data-h^=diff_mod] { color:#fff4d7; background-color:#674d06; }
h-[data-h^=mk_tag] { color:#62ded6; }
h-[data-h^=mk_attr] { color:#a4c4de; }
h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
h-[data-h^=mk_emph] { font-style:italic; }
h-[data-h^=mk_stro] { font-weight:bold; }
h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
h-[data-h^=mk_ulin] { text-decoration:underline; }
h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
h-[data-h^=mk_strk] { text-decoration:line-through; }
h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
h-[data-h^=sh_cmd] { color:#62ded6; }
h-[data-h^=sh-opt] { color:#f0f0f0; }
h-[data-h^=asm_ins] { color:#62ded6; }
h-[data-h^=asm_ins_psu] { color:#e6aee6; }
}

html.light h-[data-h^=err] { color:#ff0000; }
html.light h-[data-h^=cmt] { color:green; font-style:italic; }
html.light h-[data-h^=cmt_dlim] { font-style:normal; }
html.light h-[data-h^=val] { color:#9f6807; }
html.light h-[data-h^=num] { color:#9f6807; }
html.light h-[data-h^=str] { color:#9f6807; }
html.light h-[data-h^=esc] { color:#9f6807; }
html.light h-[data-h^=null] { color:#00607c; }
html.light h-[data-h^=bool] { color:#9f6807; }
html.light h-[data-h^=this] { color:#00607c; }
html.light h-[data-h^=mac] { color:#6f4e37; }
html.light h-[data-h^=id] { color:#000000; }
html.light h-[data-h^=id_labl] { color:#517a0b; }
html.light h-[data-h^=id_nt] { font-style:italic; }
html.light h-[data-h^=id_nt_dcl] { color:#00607c; font-style:italic; }
html.light h-[data-h^=kw] { color:#00607c; }
html.light h-[data-h^=sym] { color:#570057; }
html.light h-[data-h^=sym_punc] { color:#000000; }
html.light h-[data-h^=sym_par] { color:#af1915; }
html.light h-[data-h^=sym_sqr] { color:#af1915; }
html.light h-[data-h^=sym_brac] { color:#af1915; }
html.light h-[data-h^=diff_head] { color:#777777; }
html.light h-[data-h^=diff_head_hunk] { color:#5c477e; }
html.light h-[data-h^=diff_eq] { color:#000000; }
html.light h-[data-h^=diff_del] { color:#b31d28; background-color:#ffeef0; }
html.light h-[data-h^=diff_ins] { color:#22863a; background-color:#f0fff4; }
html.light h-[data-h^=diff_mod] { color:#7a680d; background-color:#fffdee; }
html.light h-[data-h^=mk_tag] { color:#00607c; }
html.light h-[data-h^=mk_attr] { color:#5c477e; }
html.light h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
html.light h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
html.light h-[data-h^=mk_emph] { font-style:italic; }
html.light h-[data-h^=mk_stro] { font-weight:bold; }
html.light h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
html.light h-[data-h^=mk_ulin] { text-decoration:underline; }
html.light h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
html.light h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
html.light h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
html.light h-[data-h^=mk_strk] { text-decoration:line-through; }
html.light h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
html.light h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
html.light h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
html.light h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
html.light h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
html.light h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
html.light h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
html.light h-[data-h^=sh_cmd] { color:#00607c; }
html.light h-[data-h^=sh-opt] { color:#000000; }
html.light h-[data-h^=asm_ins] { color:#00607c; }
html.light h-[data-h^=asm_ins_psu] { color:#9f6807; }

html.dark h-[data-h^=err] { color:#ff0000; }
html.dark h-[data-h^=cmt] { color:#a2e08d; font-style:italic; }
html.dark h-[data-h^=cmt_dlim] { font-style:normal; }
html.dark h-[data-h^=val] { color:#f2d18d; }
html.dark h-[data-h^=num] { color:#f2d18d; }
html.dark h-[data-h^=num_dlim] { color:#e6b191; }
html.dark h-[data-h^=num_deco] { color:#e6b191; }
html.dark h-[data-h^=str] { color:#f2d18d; }
html.dark h-[data-h^=str_dlim] { color:#e6b191; }
html.dark h-[data-h^=str_deco] { color:#e6b191; }
html.dark h-[data-h^=esc] { color:#e6aee6; }
html.dark h-[data-h^=null] { color:#62ded6; }
html.dark h-[data-h^=bool] { color:#f2d18d; }
html.dark h-[data-h^=this] { color:#62ded6; }
html.dark h-[data-h^=mac] { color:#cc946e; }
html.dark h-[data-h^=id] { color:#f0f0f0; }
html.dark h-[data-h^=id_labl] { color:#d8eda6; }
html.dark h-[data-h^=id_nt] { font-style:italic; }
html.dark h-[data-h^=id_nt_dcl] { color:#62ded6; font-style:italic; }
html.dark h-[data-h^=kw] { color:#62ded6; }
html.dark h-[data-h^=sym] { color:#baa6b9; }
html.dark h-[data-h^=sym_punc] { color:#d0d0d0; }
html.dark h-[data-h^=sym_par] { color:#fa7878; }
html.dark h-[data-h^=sym_sqr] { color:#fa7878; }
html.dark h-[data-h^=sym_brac] { color:#fa7878; }
html.dark h-[data-h^=diff_head] { color:#777777; }
html.dark h-[data-h^=diff_head_hunk] { color:#edc385; }
html.dark h-[data-h^=diff_eq] { color:#e7e7e7; }
html.dark h-[data-h^=diff_del] { color:#ffdcd7; background-color:#67060c; }
html.dark h-[data-h^=diff_ins] { color:#aff5b4; background-color:#033a16; }
html.dark h-[data-h^=diff_mod] { color:#fff4d7; background-color:#674d06; }
html.dark h-[data-h^=mk_tag] { color:#62ded6; }
html.dark h-[data-h^=mk_attr] { color:#a4c4de; }
html.dark h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
html.dark h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
html.dark h-[data-h^=mk_emph] { font-style:italic; }
html.dark h-[data-h^=mk_stro] { font-weight:bold; }
html.dark h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
html.dark h-[data-h^=mk_ulin] { text-decoration:underline; }
html.dark h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
html.dark h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
html.dark h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
html.dark h-[data-h^=mk_strk] { text-decoration:line-through; }
html.dark h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
html.dark h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
html.dark h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
html.dark h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
html.dark h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
html.dark h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
html.dark h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
html.dark h-[data-h^=sh_cmd] { color:#62ded6; }
html.dark h-[data-h^=sh-opt] { color:#f0f0f0; }
html.dark h-[data-h^=asm_ins] { color:#62ded6; }
html.dark h-[data-h^=asm_ins_psu] { color:#e6aee6; }
  </style>
  <script>
const theme = localStorage.getItem("cowel-theme");
if (theme !== null) {
    document.documentElement.className = theme;
}
  </script>
<title>More trailing commas</title></head>
<body>
<div id=settings tabindex=0>
    <div id=theme-icon></div>
    <script>
        const settings = document.getElementById("settings");
        const htmlClasses = document.documentElement.classList;
        const themeIcon = document.getElementById("theme-icon");

        settings.classList.add("js");
        themeIcon.onclick = () => {
            const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
            const overrideClass = prefersDark.matches ? "light" : "dark";
            if (htmlClasses.contains("light")) {
                htmlClasses.remove("light");
                localStorage.removeItem("cowel-theme");
            } else if (htmlClasses.contains("dark")) {
                htmlClasses.remove("dark");
                localStorage.removeItem("cowel-theme");
            } else {
                htmlClasses.add(overrideClass);
                // to avoid legal issues or controversy in general,
                // we don't mess with local storage when the page is hosted in arbitrary places
                if (window.location.protocol === "file:") {
                    localStorage.setItem("cowel-theme", overrideClass);
                }
            }
        };
        settings.onkeydown = (e) => {
            if (e.key === "Enter" || e.key === " ") {
                event.preventDefault();
                themeIcon.onclick();
            }
        };
    </script>
</div>
<main>
<style>
  ins-block .para::before {
    display: none;
  }

  .grammar dd {
    margin-top: 0;
    margin-bottom: 0;
  }

  .opt {
    font-family: var(--serif-family);
  }

  .stable-ref {
    float: right;
  }

  .five-way-poll {
    table-layout: fixed;
  }
  .five-way-poll td {
    width: 20%;
    text-align: center;
  }
</style>

<div class=wg21-head><h1>More trailing commas</h1>

<dl>
  <dt>Document number:</dt> <dd><a href=https://wg21.link/P3776R0>P3776R0</a></dd>
  <dt>Date:</dt>            <dd><tt->2025-08-27</tt-></dd>
  <dt>Audience:</dt>        <dd>EWG</dd>
  <dt>Project:</dt>         <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21</dd>
  <dt>Reply-to:</dt>        <dd>Jan Schultke &lt;<a href=mailto:janschultke@gmail.com class=sans>janschultke@gmail.com</a>&gt;</dd>
  <dt>GitHub Issue:</dt>    <dd><a href=https://wg21.link/P3776/github class=sans>wg21.link/P3776/github</a></dd>
  <dt>Source:</dt>          <dd><a href=https://github.com/eisenwave/cpp-proposals/blob/master/src/more-trailing-commas.cow class=sans>github.com/eisenwave/cpp-proposals/blob/master/src/more-trailing-commas.cow</a></dd>
</dl>
<hr/>
</div>

<abstract-block><p><intro-></intro-> 
C++ should support trailing commas in more places,
such as in function parameter lists.
</p></abstract-block>

<h2 id=contents><a class=para href=#contents></a>Contents</h2>

<div class=toc><div class=toc-num data-level=2>1</div>
<a href=#introduction><h2>Introduction</h2></a>
<div class=toc-num data-level=3>1.1</div>
<a href=#recent-history><h3>Recent history</h3></a>
<div class=toc-num data-level=3>1.2</div>
<a href=#trailing-commas-in-other-languages><h3>Trailing commas in other languages</h3></a>
<div class=toc-num data-level=2>2</div>
<a href=#motivation><h2>Motivation</h2></a>
<div class=toc-num data-level=3>2.1</div>
<a href=#improved-text-editing><h3>Improved text editing</h3></a>
<div class=toc-num data-level=3>2.2</div>
<a href=#improved-version-control><h3>Improved version control</h3></a>
<div class=toc-num data-level=3>2.3</div>
<a href=#improved-auto-formatter-control><h3>Improved auto-formatter control</h3></a>
<div class=toc-num data-level=3>2.4</div>
<a href=#improved-language-consistency><h3>Improved language consistency</h3></a>
<div class=toc-num data-level=3>2.5</div>
<a href=#va-opt><h3>Eliminating some uses of <tt-><h- data-h=mac>__VA_OPT__</h-></tt-></h3></a>
<div class=toc-num data-level=3>2.6</div>
<a href=#code-generation-convenience><h3>Code generation convenience</h3></a>
<div class=toc-num data-level=3>2.7</div>
<a href=#motivating-examples><h3>Motivating examples</h3></a>
<div class=toc-num data-level=2>3</div>
<a href=#design><h2>Design</h2></a>
<div class=toc-num data-level=3>3.1</div>
<a href=#new-trailing-commas><h3>New trailing commas</h3></a>
<div class=toc-num data-level=4>3.1.1</div>
<a href=#addressing-ambiguity-concerns><h4>Addressing ambiguity concerns</h4></a>
<div class=toc-num data-level=3>3.2</div>
<a href=#already-supported-trailing-commas><h3>Already supported trailing commas</h3></a>
<div class=toc-num data-level=3>3.3</div>
<a href=#not-proposed-trailing-commas><h3>Not proposed trailing commas</h3></a>
<div class=toc-num data-level=4>3.3.1</div>
<a href=#commas-proposed-in-p0562r2><h4>Commas proposed in P0562R2</h4></a>
<div class=toc-num data-level=4>3.3.2</div>
<a href=#trailing-commas-in-semicolon-terminated-lists><h4>Trailing commas in semicolon-terminated lists</h4></a>
<div class=toc-num data-level=4>3.3.3</div>
<a href=#non-lists><h4>Non-lists</h4></a>
<div class=toc-num data-level=4>3.3.4</div>
<a href=#commas-following-ellipsis-parameters><h4>Commas following ellipsis parameters</h4></a>
<div class=toc-num data-level=4>3.3.5</div>
<a href=#commas-in-macros><h4>Commas in macros</h4></a>
<div class=toc-num data-level=3>3.4</div>
<a href=#comparison-to-p0562r2><h3>Comparison to P0562R2</h3></a>
<div class=toc-num data-level=3>3.5</div>
<a href=#could-this-syntax-be-used-for-something-else><h3>Could this syntax be used for something else?</h3></a>
<div class=toc-num data-level=3>3.6</div>
<a href=#addressing-criticisms><h3>Addressing criticisms</h3></a>
<div class=toc-num data-level=4>3.6.1</div>
<a href=#aesthetic-objections><h4>Aesthetic objections</h4></a>
<div class=toc-num data-level=4>3.6.2</div>
<a href=#concerns-over-c-compatibility><h4>Concerns over C compatibility</h4></a>
<div class=toc-num data-level=4>3.6.3</div>
<a href=#making-previously-ill-formed-code-valid><h4>Making previously ill-formed code valid</h4></a>
<div class=toc-num data-level=4>3.6.4</div>
<a href=#semantic-inconsistencies-with-macros><h4>Semantic inconsistencies with macros</h4></a>
<div class=toc-num data-level=4>3.6.5</div>
<a href=#multiple-ways-to-do-the-same-thing><h4>Multiple ways to do the same thing</h4></a>
<div class=toc-num data-level=2>4</div>
<a href=#implementation-experience><h2>Implementation experience</h2></a>
<div class=toc-num data-level=2>5</div>
<a href=#impact-on-existing-code><h2>Impact on existing code</h2></a>
<div class=toc-num data-level=2>6</div>
<a href=#wording><h2>Wording</h2></a>
<div class=toc-num data-level=2>7</div>
<a href=#references><h2>References</h2></a>
</div>

<h2 id=introduction><a class=para href=#introduction></a>1. Introduction</h2>

<p>C++ permits the use of trailing commas in some lists, but not in others.
For example, trailing commas are permitted at the end of an <g-term>initializer-list</g-term>,
but not following a
<g-term>mem-initializer-list</g-term>,
<g-term>capture-list</g-term>,
<g-term>template-parameter-list</g-term>,
<g-term>expression-list</g-term>,
in a <g-term>postfix-expression</g-term>, etc.
It would be convenient if the support for trailing commas was extended
to those other lists.
</p>
<p>For example, the following should be valid:
</p>
<code-block><h- data-h=kw_type>void</h-> <h- data-h=id>f</h-><h- data-h=sym_par>(</h->
    <h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>int</h-> <h- data-h=id>y</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> trailing comma here</h->
<h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<h3 id=recent-history><a class=para href=#recent-history></a>1.1. Recent history</h3>

<p>While this proposal is new,
a very similar proposal <a href="https://wg21%2elink/p0562r2">[P0562R2]</a> has recently passed through EWG and CWG,
but was ultimately not polled due to implementability concerns.
<a href="https://wg21%2elink/p0562r2">[P0562R2]</a> argues in favor of trailing commas
following <g-term>mem-initializer-list</g-term> and <g-term>base-specifier-list</g-term>,
with similar rationale as this proposal.
The concern in question is that a comma after a <g-term>mem-initializer-list</g-term>
introduces a parsing ambiguity
between expressions and function bodies;
see <a href="https://lists%2eisocpp%2eorg/core/2024/06/15961%2ephp">[P0562R2ReflectorDiscussion]</a>:
</p>
<blockquote>
<p>Classes are parsed in two phases: first, declarations are parsed, skipping
the bodies of member functions and a few other things, and then those
delayed parts are parsed in a context where the class is complete. 
</p>
<p>For most functions, skipping the body in the first pass is easy. There's an
open brace, and you can just skip to the close brace. At worst, there's
<code><h- data-h=kw>try</h-> <h- data-h=sym_brac>{</h-></code>,
and you need to find the end of the last catch handler.
</p>
<p>The problem is that a
<g-term>mem-initializer-id</g-term> can be a <g-term>template-id</g-term> that refers to a base class, and
the identifiers it uses to name the base class might be declared
(possibly after the constructor) in the same class — meaning that we've not parsed
them yet.
Therefore when we see a <code><h- data-h=sym_op>&lt;</h-></code>, we don't know if it's introducing a
template argument list.
For example: 
</p>
<code-block><h- data-h=kw>struct</h-> <h- data-h=id>X</h-> <h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>struct</h-> <h- data-h=id>Y</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>X</h-> <h- data-h=sym_brac>{</h->
  <h- data-h=id>Y</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>A</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>b</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>c</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_brac>{</h->
  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> ...</h->
  <h- data-h=sym_brac>}</h->
  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> A, b, and c declared down here somewhere</h->
<h- data-h=sym_brac>}</h-><h- data-h=sym_punc>;</h-></code-block>

<p>Are we in the body of the constructor yet?
</p>
<p>Prior to P0562R2, the answer was no: an open brace preceded by a comma
cannot start the constructor body. For this to be valid, <code><h- data-h=id>b</h-></code> must be a
template, and the <code><h- data-h=sym_brac>{</h-></code> is then the start
of the second template argument of <code><h- data-h=id>A</h-></code>. ([…]) 
</p>
<p>But after P0562R2, the above example seems to become ambiguous, and I'm not
sure how an implementation would be able to parse it.
</p></blockquote>

<p>Following these developments in St. Louis 2024-06,
the proposal has seen no activity.
It seems like the baby has been thrown out with the bathwater here,
since the rationale of the proposal is still sound and
this ambiguity does not affect <g-term>base-specifier-list</g-term>s.
</p>
<h3 id=trailing-commas-in-other-languages><a class=para href=#trailing-commas-in-other-languages></a>1.2. Trailing commas in other languages</h3>

<p>Various modern programming languages support trailing commas,
not just in initialization of classes or when listing <code><h- data-h=kw>enum</h-></code> members,
but also in function parameter lists or function argument lists:
</p>
<style>
  #lang-table {
    margin-left: auto;
    margin-right: auto;
    width: 95%;
  }
  #lang-table td {
    padding-bottom: 1em;
  }
</style>

<table id=lang-table>
  <tr>
    <th>Language</th> <th>Trailing commas support</th>
  </tr>
  <tr>
    <td>Rust</td>
    <td>
      Has always supported trailing commas in.<br/>
      Use of trailing commas is recommended by the official style guide
      (<a href="https://doc%2erust-lang%2eorg/style-guide/#trailing-commas">[RustTrailingCommas]</a>).
    </td>
  </tr>
  <tr>
    <td>Kotlin</td>
    <td>
      Added support for trailing commas in 2020 (<a href="https://kotlinlang%2eorg/docs/whatsnew14%2ehtml#trailing-comma">[KotlinTrailingCommas]</a>).
    </td>
  </tr>
  <tr>
    <td>JavaScript</td>
    <td>
      Support for trailing commas was standardized in ECMASCript2017
      (<a href="https://github%2ecom/tc39/proposal-trailing-function-commas">[ECMAScriptTrailingCommas]</a>).
    </td>
  </tr>
  <tr>
    <td>TypeScript</td>
    <td>
      Added support at the same time it was standardized for JavaScript
      (<a href="https://www%2etypescriptlang%2eorg/docs/handbook/release-notes/typescript-2-0%2ehtml#trailing-commas-in-function-parameter-and-argument-lists">[TypeScriptTrailingCommas]</a>).
    </td>
  </tr>
  <tr>
    <td>C#</td>
    <td>
      No support yet,
      in part due to concerns regarding tuple syntax,
      which also uses parentheses (<a href="https://github%2ecom/dotnet/csharplang/issues/1246">[CSharpTrailingCommas]</a>).
    </td>
  </tr>
  <tr>
    <td>Swift</td>
    <td>
      No support yet.
      Concerns regarding tuple syntax have also been raised (<a href="https://forums%2eswift%2eorg/t/allow-trailing-commas-in-parameter-lists/68549/29">[SwiftTrailingCommas]</a>).
    </td>
  </tr>
</table>

<p>The motivation for trailing commas in those languages equally applies to C++.
</p>
<note-block><p><intro-></intro-> 
More discussion on this language design choice can also be found at
<a href="https://www%2ereddit%2ecom/r/ProgrammingLanguages/comments/1amsalm/does_your_language_support_trailing_commas/">[RedditTrailingCommas]</a> and <a href="https://devblogs%2emicrosoft%2ecom/oldnewthing/20240209-00/?p=109379">[OldNewThing]</a>.
</p>
<p>Various other languages such as Python, Go, and Julia also support
trailing commas in function calls,
but are not specially listed in the table above.
That table aims to highlight particularly relevant examples with authoritative resources.
</p></note-block>

<h2 id=motivation><a class=para href=#motivation></a>2. Motivation</h2>

<p>While trailing commas don't solve any major safety or performance issue,
they improve developer convenience significantly in some ways.
Given how many comma-separated lists developers regularly write,
this convenience can be noticeable on a daily basis.
</p>
<note-block><p><intro-></intro-> 
The following motivation uses only function parameter lists as motivating examples,
but the arguments equally apply to other comma-separated lists.
</p></note-block>

<h3 id=improved-text-editing><a class=para href=#improved-text-editing></a>2.1. Improved text editing</h3>

<p>Advanced text editors typically have commands for cutting/copying whole lines,
or let the developer reorder lines via keyboard shortcut.
For example, a line can be swapped with the line above
with <kbd>Alt</kbd>+<kbd> ↑ </kbd> in VSCode.
This can result in compiler errors without trailing commas:
</p>
<code-block><h- data-h=kw_type>void</h-> <h- data-h=id>f</h-><h- data-h=sym_par>(</h->
    <h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>int</h-> <h- data-h=id>y</h->
<h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<p>When reordering <code><h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-></code> and <code><h- data-h=kw_type>int</h-> <h- data-h=id>y</h-></code>, errors are raised:
</p>
<code-block><h- data-h=kw_type>void</h-> <h- data-h=id>f</h-><h- data-h=sym_par>(</h->
    <h- data-h=kw_type>int</h-> <h- data-h=id>y</h->  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>↲</h-><h- data-h=cmt> syntax error: "int" following "y"</h->
    <h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> syntax error: trailing comma</h->
<h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<p>If both lines had a trailing comma and C++ permitted that syntax,
reordering these lines would not be a problem.
</p>
<h3 id=improved-version-control><a class=para href=#improved-version-control></a>2.2. Improved version control</h3>

<p>When an element is appended to a comma-separated list,
this means that the previous element needs to receive a separating comma,
resulting in menial changes:
</p>
<code-block><h- data-h=diff_eq> void f(</h->
<h- data-h=diff_eq>     int x,</h->
<h- data-h=diff_del>-    int y</h->
<h- data-h=diff_ins>+    int y,</h->
<h- data-h=diff_ins>+    int z</h->
<h- data-h=diff_eq> );</h-></code-block>

<p>With trailing commas, we can turn a three-line change into a one-line change:
</p>
<code-block><h- data-h=diff_eq> void f(</h->
<h- data-h=diff_eq>     int x,</h->
<h- data-h=diff_eq>     int y,</h->
<h- data-h=diff_ins>+    int z,</h->
<h- data-h=diff_eq> );</h-></code-block>

<p>This smaller change is not just easier to review,
it also does not pollute the revision history (<tt->git blame</tt->) for
the previous line of code,
and it does not introduce easily avoidable merge conflicts.
</p>
<h3 id=improved-auto-formatter-control><a class=para href=#improved-auto-formatter-control></a>2.3. Improved auto-formatter control</h3>

<p>Many C++ developers auto-format their code using
<a href=https://clang.llvm.org/docs/ClangFormat.html>ClangFormat</a>.
One powerful feature it has is the ability to control
how brace-enclosed lists are formatted via the use of trailing commas.
</p>
<example-block><p><intro-></intro-> 
ClangFormat may format C++ code like:
</p><code-block><h- data-h=id>vector</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>int</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=id>numbers</h-> <h- data-h=sym_brac>{</h-> <h- data-h=id>LIST_ITEM_A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>LIST_ITEM_B</h-><h- data-h=sym_punc>,</h->  <h- data-h=cmt_dlim>//</h->
                      <h- data-h=id>LIST_ITEM_C</h-> <h- data-h=sym_brac>}</h-><h- data-h=sym_punc>;</h->             <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> column limit here</h->
                                                 <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h->
<h- data-h=id>vector</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>int</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=id>numbers</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=id>LIST_ITEM_A</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>LIST_ITEM_B</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>LIST_ITEM_C</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> trailing comma here</h->
<h- data-h=sym_brac>}</h-><h- data-h=sym_punc>;</h-></code-block>

<p>The compact version without a trailing comma may be situationally useful
by compactifying code, allowing more to fit on screen.
The verbose version with a trailing comma is more useful for regularly updated lists,
and can be perceived as more organized.
It's easy to envision the same example with function argument lists.
</p></example-block>

<p>Trailing commas express the desire to format over multiple lines,
which auto-formatters may utilize.
Without support for trailing commas in e.g. function parameter lists,
the developer is robbed of their ability to (elegantly) express that desire,
since doing so would make the program ill-formed.
</p>
<note-block><p><intro-></intro-> 
A possible workaround for ClangFormat is to insert a trailing <code><h- data-h=cmt_dlim>//</h-></code>
at the end of a line
(which forces line breaks to be retained),
or to manually format a section of code with <code><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> clang-format off</h-></code>.
</p></note-block>

<h3 id=improved-language-consistency><a class=para href=#improved-language-consistency></a>2.4. Improved language consistency</h3>

<p>It is generally surprising that C++ only supports trailing commas
within a subset of its comma-separated lists.
Besides the design not sparking joy,
it creates practical problems.
</p>
<p>For example, when refactoring code and e.g. converting list-initialization
such as <code><h- data-h=sym_brac>{</h-><h- data-h=num>1</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>2</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>3</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_brac>}</h-></code> which already uses trailing commas into direct-initialization
<code><h- data-h=sym_par>(</h-><h- data-h=num>1</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>2</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>3</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-></code>,
the trailing comma introduces a compiler error until it is removed,
which is a mild inconvenience at least.
</p>
<h3 id=va-opt><a class=para href=#va-opt></a>2.5. Eliminating some uses of <tt-><h- data-h=mac>__VA_OPT__</h-></tt-></h3>

<p>When we want to prepend an element to a variadic macro argument,
we may need to use <tt-><h- data-h=mac>__VA_OPT__</h-></tt-> in the following way:
</p>
<code-block><h- data-h=mac>#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)</h->
<h- data-h=mac>#define L(...) [&amp; __VA_OPT__(,) __VA_ARGS__] {}</h-></code-block>

<p>With an unconditional comma,
<code><h- data-h=mac>F</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-></code> would expand to <code><h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-></code>,
which is currently ill-formed.
A trailing comma in function calls and other lists would allow us to simplify such macros.
</p>
<note-block><p><intro-></intro-> 
While a <g-term>capture-default</g-term> like <code><h- data-h=sym_op>&amp;</h-></code> is not part of the <g-term>capture-list</g-term>,
a trailing comma should still be permitted following it.
Otherwise, the example above would still be broken.
</p></note-block>

<h3 id=code-generation-convenience><a class=para href=#code-generation-convenience></a>2.6. Code generation convenience</h3>

<p>Allowing trailing commas makes it easier to generate C++ code,
for similar reasons as in <a href=#va-opt>§2.5. Eliminating some uses of <tt-><h- data-h=mac>__VA_OPT__</h-></tt-></a>.
Generating lists is sometimes made easier if each element in a list can
be terminated by a comma, rather than adding special handling for the first/last element
to ensure no trailing commas in generated code.
</p>
<example-block><p><intro-></intro-> 
Code generation for a list of function parameters
is simplified by trailing commas in C++ as follows:
</p><code-block><h- data-h=kw_type>void</h-> <h- data-h=id>emit_parameters</h-><h- data-h=sym_par>(</h-><h- data-h=id>span</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>const</h-> <h- data-h=id>Parameter</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=id>parameters</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=id>emit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>(</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
    <del><h- data-h=kw_type>bool</h-> <h- data-h=id>first</h-> <h- data-h=sym_op>=</h-> <h- data-h=bool>true</h-><h- data-h=sym_punc>;</h-></del>
    <h- data-h=kw_ctrl>for</h-> <h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=kw>auto</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>p</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>parameters</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
<del>        <h- data-h=kw_ctrl>if</h-> <h- data-h=sym_par>(</h-><h- data-h=sym_op>!</h-><h- data-h=id>first</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
            <h- data-h=id>emit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>,</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
        <h- data-h=sym_brac>}</h->
        <h- data-h=id>first</h-> <h- data-h=sym_op>=</h-> <h- data-h=bool>false</h-><h- data-h=sym_punc>;</h-></del>
        <h- data-h=id>emit_parameter</h-><h- data-h=sym_par>(</h-><h- data-h=id>p</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<ins>        <h- data-h=id>emit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>,</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></ins>
    <h- data-h=sym_brac>}</h->
    <h- data-h=id>emit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>)</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h-></code-block>
</example-block>

<h3 id=motivating-examples><a class=para href=#motivating-examples></a>2.7. Motivating examples</h3>

<p>In discussions of this proposal,
there is often some skepticism as to whether it's useful for specific lists.
For example, I have been told that trailing commas may be useful
in a <g-term>template-parameter-list</g-term>, but not in a <g-term>template-argument-list</g-term>.
However, while some lists are more frequently multi-line,
you can come up with a plausible multi-line example for virtually any list:
</p>
<code-block><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-parameter-list</h-></g-term></f-serif>
<h- data-h=kw>template</h-> <h- data-h=sym_op>&lt;</h->
    <h- data-h=id>input_iterator</h-> <h- data-h=id>I</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>sentinel_for</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>I</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=id>S</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>weakly_incrementable</h-> <h- data-h=id>O</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>trailing comma here</h-></f-serif>
<h- data-h=sym_op>&gt;</h->
<h- data-h=id>copy_result</h-> <h- data-h=id>function</h-><h- data-h=sym_par>(</h-><h- data-h=id>I</h-> <h- data-h=id>first</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>S</h-> <h- data-h=id>last</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>O</h-> <h- data-h=id>result</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-argument-list</h-></g-term></f-serif>
<h- data-h=kw>using</h-> <h- data-h=id>V</h-> <h- data-h=sym_op>=</h-> <h- data-h=id>variant</h-><h- data-h=sym_op>&lt;</h->
    <h- data-h=id_type>int_least64_t</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>float</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>double</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>char8_t</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>char16_t</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>char32_t</h-><h- data-h=sym_punc>,</h->
    <h- data-h=kw_type>bool</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>string</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>trailing comma here</h-></f-serif>
<h- data-h=sym_op>&gt;</h-><h- data-h=sym_punc>;</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>function-parameter-list</h-></g-term></f-serif>
<h- data-h=kw_type>void</h-> <h- data-h=id>pretty_print_log</h-><h- data-h=sym_par>(</h->
    <h- data-h=id>log_level</h-> <h- data-h=id>level</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>string_view</h-> <h- data-h=id>message</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>optional</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>code_location</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=id>location</h-> <h- data-h=sym_op>=</h-> <h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>optional</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>const</h-> <h- data-h=id>error</h-><h- data-h=sym_op>&amp;</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=id>error</h-> <h- data-h=sym_op>=</h-> <h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>trailing comma here</h-></f-serif>
<h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>function-argument-list</h-></g-term></f-serif>
<h- data-h=kw>auto</h-> <h- data-h=id>it</h-> <h- data-h=sym_op>=</h-> <h- data-h=id>find</h-><h- data-h=sym_par>(</h->
    <h- data-h=id>ranges</h-><h- data-h=sym_op>::</h-><h- data-h=id>begin</h-><h- data-h=sym_par>(</h-><h- data-h=id>container</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>ranges</h-><h- data-h=sym_op>::</h-><h- data-h=id>end</h-><h- data-h=sym_par>(</h-><h- data-h=id>container</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>+</h-> <h- data-h=sym_par>(</h-><h- data-h=id>container</h-><h- data-h=sym_op>.</h-><h- data-h=id>size</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>/</h-> <h- data-h=num>2</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>trailing comma here</h-></f-serif>
<h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>lambda-capture</h-></g-term></f-serif>
<h- data-h=kw>auto</h-> <h- data-h=id>callback</h-> <h- data-h=sym_op>=</h-> <h- data-h=sym_sqr>[</h->
        <h- data-h=sym_op>&amp;</h-><h- data-h=sym_punc>,</h->
        <h- data-h=id>current_index</h-> <h- data-h=sym_op>=</h-> <h- data-h=num>0</h-><h- data-h=sym_punc>,</h->
        <h- data-h=id>invocation_count</h-> <h- data-h=sym_op>=</h-> <h- data-h=num>0</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>trailing comma here</h-></f-serif>
    <h- data-h=sym_sqr>]</h-> <h- data-h=sym_brac>{</h->
        <h- data-h=sym_op>++</h-><h- data-h=id>invocation_count</h-><h- data-h=sym_punc>;</h->
        <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> ...</h->
    <h- data-h=sym_brac>}</h-><h- data-h=sym_punc>;</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>annotation-list</h-></g-term></f-serif>
<h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>[</h->
    <h- data-h=sym_op>=</h-> <h- data-h=id>testing</h-><h- data-h=sym_op>::</h-><h- data-h=id>description</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>"</h-><h- data-h=str>Fuzzing test for ASCII sequences.</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>,</h->
    <h- data-h=sym_op>=</h-> <h- data-h=id>testing</h-><h- data-h=sym_op>::</h-><h- data-h=id>execution</h-><h- data-h=sym_op>::</h-><h- data-h=id>parallel</h-><h- data-h=sym_punc>,</h-> <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><h- data-h=cmt>←</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>trailing comma here</h-></f-serif>
<h- data-h=sym_sqr>]</h-><h- data-h=sym_sqr>]</h->
<h- data-h=kw_type>void</h-> <h- data-h=id>fuzz_ascii</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h-> <h- data-h=cmt_dlim>/*</h-><h- data-h=cmt> ... </h-><h- data-h=cmt_dlim>*/</h-> <h- data-h=sym_brac>}</h-></code-block>

<p>For any of these list types, it is plausible that they are long enough
to be broken onto multiple lines,
and it is plausible that changes will be made to such lists in the future,
which makes a trailing comma useful in these lists.
</p>
<h2 id=design><a class=para href=#design></a>3. Design</h2>

<p>I propose to add a trailing comma after a list whenever possible
(i.e. no parsing issues are introduced),
with the exception of lists terminated by a semicolon.
The design can be summed up as:
</p>
<blockquote>
<p>When enclosed by <code><h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h-></code>, <code><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-></code>, <code><h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>]</h-></code>, or <code><h- data-h=sym_op>&lt;</h-><h- data-h=sym_op>&gt;</h-></code>,
lists can have a trailing comma.
</p></blockquote>

<p>All the following decisions are intended to make that rule of thumb correct.
Cherry-picking individual cases like permitting <code><h- data-h=id>array</h-><h- data-h=sym_sqr>[</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-><h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h-></code>
but not <code><h- data-h=sym_sqr>[</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-><h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h-></code> would only complicate the situation.
</p>
<h3 id=new-trailing-commas><a class=para href=#new-trailing-commas></a>3.1. New trailing commas</h3>

<p>The following trailing commas are proposed,
and not currently permitted.
</p>
<code-block><h- data-h=sym_sqr>[</h-><h- data-h=sym_punc>:</h-> <h- data-h=cmt_dlim>/*</h-><h- data-h=cmt> ... </h-><h- data-h=cmt_dlim>*/</h-> <h- data-h=sym_punc>:</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>B</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h->              <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-argument-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>splice-specialization-specifier</h-></g-term></f-serif>
<h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>B</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h->                         <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-parameter-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>lambda-expression</h-></g-term></f-serif>
<h- data-h=sym_sqr>[</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h->                           <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>capture-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>lambda-introducer</h-></g-term></f-serif>
<h- data-h=id>d</h-><h- data-h=sym_sqr>[</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h->                            <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in subscript operator</h-></f-serif>
<h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->                            <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in call operator</h-></f-serif>
<h- data-h=id>T</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->                               <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in function-style cast</h-></f-serif>
<h- data-h=kw>typename</h-> <h- data-h=id>T</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->                      <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in function-style cast with </h-><code><h- data-h=kw>typename</h-></code></f-serif>
<h- data-h=kw>new</h-> <h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-> <h- data-h=id>T</h->                       <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>new-placement</h-></g-term></f-serif>
<h- data-h=kw>new</h-> <h- data-h=id>T</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->                        <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>new-initializer</h-></g-term></f-serif>
<h- data-h=kw>template</h-> <h- data-h=kw_ctrl>for</h-> <h- data-h=sym_par>(</h-><h- data-h=kw_type>int</h-> <h- data-h=id>_</h-> <h- data-h=sym_punc>:</h-> <h- data-h=sym_brac>{</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_brac>}</h-><h- data-h=sym_par>)</h->    <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>expansion-init-list</h-></g-term></f-serif>
<h- data-h=kw>auto</h-> <h- data-h=sym_sqr>[</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h->                        <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>sb-identifier-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>structured-binding-declaration</h-></g-term></f-serif>
<h- data-h=id>T</h-> <h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->                          <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>parameter-declaration-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>parameter-declaration-clause</h-></g-term></f-serif>
<h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->                         <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>initializer</h-></g-term></f-serif>
<h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>[</h-><h- data-h=sym_op>=</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_op>=</h-><h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_sqr>]</h->                         <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>annotation-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>attribute-specifier</h-></g-term></f-serif>
<h- data-h=id>S</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>m</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->                      <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>expression-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>mem-initializer</h-></g-term></f-serif>
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h->                     <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-parameter-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>template-head</h-></g-term></f-serif>
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>C</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->                <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-argument-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>type-constraint</h-></g-term></f-serif>
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>B</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=kw>concept</h-><h- data-h=sym_op>&gt;</h->   <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-parameter-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>concept-tt-parameter</h-></g-term></f-serif>
<h- data-h=id>T</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>B</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h->                            <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-argument-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>simple-template-id</h-></g-term></f-serif>
<h- data-h=kw>operator</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>B</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h->                   <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>template-argument-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>template-id</h-></g-term></f-serif></code-block>

<p>While this initially appears like a huge change,
it can be easily worded by incorporating the trailing comma directly
into lists such as <g-term>expression-list</g-term>,
since every occurrence of these lists would allow for trailing commas.
</p>
<note-block><p><intro-></intro-> 
Of these, the <g-term>expression-list</g-term> in an <g-term>expansion-init-list</g-term> seems like a C++26 defect,
and a CWG issue has been requested at <a href="https://github%2ecom/cplusplus/CWG/issues/754">[CWGGithub754]</a>.
Since this appears to be a separate C++26 defect,
not a new C++29 feature,
this paper's wording does not include that fix.
</p></note-block>

<note-block><p><intro-></intro-> 
Trailing commas would also be supported following a <g-term>capture-default</g-term>,
such as in <code><h- data-h=sym_sqr>[</h-><h- data-h=sym_op>&amp;</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h-></code>.
This is worth mentioning because a <g-term>capture-default</g-term> is not actually part of a
<g-term>capture-list</g-term>, but a standalone element within a <g-term>lambda-capture</g-term>.
</p></note-block>

<h4 id=addressing-ambiguity-concerns><a class=para href=#addressing-ambiguity-concerns></a>3.1.1. Addressing ambiguity concerns</h4>

<p>Note that all of these proposed cases are safe from parsing ambiguities
encountered by <a href="https://wg21%2elink/p0562r2">[P0562R2]</a>.
That is because a the trailing comma can only be followed by
'<code><h- data-h=sym_brac>}</h-></code>',
'<code><h- data-h=sym_par>)</h-></code>',
'<code><h- data-h=sym_sqr>]</h-></code>', or
'<code><h- data-h=sym_op>&gt;</h-></code>'.
In the first three cases,
a closing bracket cannot possibly be the beginning of a new element,
only the end whatever encloses list.
Neither '<code><h- data-h=sym_op>&gt;</h-></code>', '<code><h- data-h=sym_op>&gt;=</h-></code>', nor '<code><h- data-h=sym_op>&gt;&gt;</h-></code>' are prefix unary operators,
so in any case, '<code><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h-></code>' can only mean one thing.
</p>
<p>Furthermore, <code><h- data-h=kw>operator</h-><h- data-h=sym_punc>,</h-></code> cannot be separated into <code><h- data-h=kw>operator</h-></code> and '<code><h- data-h=sym_punc>,</h-></code>'
or combined into <code><h- data-h=kw>operator</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h-></code> (there is no '<code><h- data-h=sym_punc>,</h-><h- data-h=sym_op>&gt;</h-></code>' operator in the language),
so no ambiguity can be introduced by having <code><h- data-h=kw>operator</h-></code> appear at the end of a list.
</p>
<h3 id=already-supported-trailing-commas><a class=para href=#already-supported-trailing-commas></a>3.2. Already supported trailing commas</h3>

<p>The following trailing commas are already supported:
</p>
<code-block><h- data-h=sym_brac>{</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_brac>}</h->                 <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>initializer-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>braced-init-list</h-></g-term></f-serif>
<h- data-h=sym_brac>{</h-> <h- data-h=sym_op>.</h-><h- data-h=id>a</h-><h- data-h=sym_op>=</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_op>.</h-><h- data-h=id>b</h-><h- data-h=sym_op>=</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_brac>}</h->           <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>designated-initializer-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>braced-init-list</h-></g-term></f-serif>
<h- data-h=kw>enum</h-> <h- data-h=sym_brac>{</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_brac>}</h->            <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>enumerator-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>enum-specifier</h-></g-term></f-serif>
<h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>[</h-><h- data-h=id>a</h-><h- data-h=sym_punc>,</h-><h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_sqr>]</h->               <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>attribute-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>attribute-specifier</h-></g-term></f-serif></code-block>

<h3 id=not-proposed-trailing-commas><a class=para href=#not-proposed-trailing-commas></a>3.3. Not proposed trailing commas</h3>

<h4 id=commas-proposed-in-p0562r2><a class=para href=#commas-proposed-in-p0562r2></a>3.3.1. Commas proposed in P0562R2</h4>

<p>The following two trailing commas are proposed by <a href="https://wg21%2elink/p0562r2">[P0562R2]</a> and should be added,
if at all possible,
as a revision of that paper.
</p>
<code-block><h- data-h=id>S</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>a</h-><h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_brac>{</h-><h- data-h=sym_brac>}</h-><h- data-h=sym_punc>,</h->           <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>mem-initializer-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>ctor-initializer</h-></g-term></f-serif>
<h- data-h=kw>struct</h-> <h- data-h=id>S</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>B</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_brac>{</h-> <h- data-h=sym_brac>}</h-><h- data-h=sym_punc>;</h->     <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>base-specifier-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>base-clause</h-></g-term></f-serif></code-block>

<p>While the parsing ambiguity (<a href=#recent-history>§1.1. Recent history</a>)
seems limited to a <g-term>mem-initializer-list</g-term>,
a <g-term>base-specifier-list</g-term> is similarly followed by <code><h- data-h=sym_brac>{</h-></code>,
which makes it quite plausible that similar parsing issues could affect that case.
In any case, to keep this paper focused,
I do not propose those two commas.
</p>
<h4 id=trailing-commas-in-semicolon-terminated-lists><a class=para href=#trailing-commas-in-semicolon-terminated-lists></a>3.3.2. Trailing commas in semicolon-terminated lists</h4>

<p>Two more commas are not proposed because they are in semicolon-terminated lists:
</p>
<code-block><h- data-h=kw_type>int</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>;</h->                <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>init-declarator-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>simple-declaration</h-></g-term></f-serif>
<h- data-h=kw>struct</h-> <h- data-h=id>S</h-> <h- data-h=sym_brac>{</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>;</h-> <h- data-h=sym_brac>}</h-><h- data-h=sym_punc>;</h->  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>member-declarator-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>member-declaration</h-></g-term></f-serif>
<h- data-h=kw>friend</h-> <h- data-h=id>A</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>B</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>;</h->             <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>friend-type-specifier-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>friend-type-declaration</h-></g-term></f-serif>
<h- data-h=kw>using</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>;</h->              <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>using-declarator-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>using-declaration</h-></g-term></f-serif></code-block>

<p>Firstly, for aesthetic reasons, it is unlikely that users would want to write this.
Furthermore, multiple elements in a <g-term>init-declarator-list</g-term> are already
discouraged by some style guides.
Last but not least, the <a href=#motivation>§2. Motivation</a> of this paper focuses on multi-line scenarios.
In the aforementioned cases,
to make good use of trailing commas,
developers would need to write:
</p>
<code-block><h- data-h=kw_type>int</h->
    <h- data-h=id>a</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>b</h-><h- data-h=sym_punc>,</h->
<h- data-h=sym_punc>;</h->

<h- data-h=kw>using</h->
    <h- data-h=id>a</h-><h- data-h=sym_punc>,</h->
    <h- data-h=id>b</h-><h- data-h=sym_punc>,</h->
<h- data-h=sym_punc>;</h-></code-block>

<p>Not only is this exotic, it is also more verbose than the status quo,
which already allows reordering lines if we instead write:
</p>
<code-block><h- data-h=kw_type>int</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw_type>int</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>;</h->

<h- data-h=kw>using</h-> <h- data-h=id>a</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>b</h-><h- data-h=sym_punc>;</h-></code-block>

<p>Overall, permitting trailing commas
in a <g-term>init-declarator-list</g-term> or <g-term>using-declarator-list</g-term> seems unmotivated,
and would create unnecessary work for implementers.
</p>
<h4 id=non-lists><a class=para href=#non-lists></a>3.3.3. Non-lists</h4>

<p>The following trailing commas are not proposed because they are not following a list:
</p>
<code-block><h- data-h=kw>static_assert</h-><h- data-h=sym_par>(</h-><h- data-h=bool>true</h-><h- data-h=sym_punc>,</h-><h- data-h=str_dlim>"</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->   <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>static_assert-declaration</h-></g-term></f-serif>
<h- data-h=kw>contract_assert</h-><h- data-h=sym_par>(</h-><h- data-h=bool>true</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->    <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>assertion-statement</h-></g-term></f-serif>
<h- data-h=sym_op>=</h-> <h- data-h=kw>delete</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>"</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->             <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>deleted-function-body</h-></g-term></f-serif></code-block>

<p>While it may be more philosophically consistent to permit a comma within anything
that vaguely looks like a function call,
there is little motivation for such cases above.
To be fair, a trailing comma could yield a minimal one-line change as follows:
</p>
<code-block><h- data-h=diff_eq> static_assert(</h->
<h- data-h=diff_eq>     true,</h->
<h- data-h=diff_ins>+    "message"</h->
<h- data-h=diff_eq> );</h-></code-block>

<p>However, it seems unlikely that a developer would choose to distribute a no-message
<code><h- data-h=kw>static_assert</h-></code> over three lines in the first place.
Overall, these cases just seem to add more work for implementers.
</p>
<h4 id=commas-following-ellipsis-parameters><a class=para href=#commas-following-ellipsis-parameters></a>3.3.4. Commas following ellipsis parameters</h4>

<p>Another not proposed trailing comma is that after an ellipsis parameter:
</p>
<code-block><h- data-h=kw_type>void</h-> <h- data-h=id>f</h-><h- data-h=sym_par>(</h->
  <h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h->
  <h- data-h=sym_op>...</h-><h- data-h=sym_punc>,</h->    <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>after </h-><code><h- data-h=sym_op>...</h-></code><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>parameter-declaration-clause</h-></g-term></f-serif>
<h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<p>This decision is largely based on negative feedback in <a href="https://lists%2eisocpp%2eorg/core/2025/08/18487%2ephp">[CoreReflectorDiscussion]</a>.
</p>
<p>The trailing comma in this place is largely unmotivated because the ellipsis is always
the last element in the list.
Consequently, a <code><h- data-h=sym_op>...</h-></code> line cannot be reordered with the line before,
and a comma will never have to be inserted after <code><h- data-h=sym_op>...</h-></code> to accommodate a subsequent element.
</p>
<h4 id=commas-in-macros><a class=para href=#commas-in-macros></a>3.3.5. Commas in macros</h4>

<p>The following trailing commas are not proposed:
</p>
<code-block><h- data-h=mac>#define M(x,y,) </h-><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><g-term><h- data-h=cmt>identifier-list</h-></g-term><h- data-h=cmt> in </h-><g-term><h- data-h=cmt>control-line</h-></g-term></f-serif>
<h- data-h=mac>M</h-><h- data-h=sym_par>(</h-><h- data-h=id>x</h-><h- data-h=sym_punc>,</h-><h- data-h=id>y</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h->         <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>arguments to a function-like macro</h-></f-serif></code-block>

<p>The former lacks motivation because it is highly unlikely
that a C++ use would define multi-line parameters to a function-style macro.
Doing so requires each parameter line to be terminated by <code>\</code>,
among other reasons.
</p>
<p>Supporting trailing commas in <code><h- data-h=mac>M</h-><h- data-h=sym_par>(</h-><h- data-h=id>x</h-><h- data-h=sym_punc>,</h-><h- data-h=id>y</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-></code>
would alter the meaning of existing code.
Currently, that expression is providing three arguments to <code><h- data-h=mac>M</h-></code>,
the last of which is empty.
</p>
<h3 id=comparison-to-p0562r2><a class=para href=#comparison-to-p0562r2></a>3.4. Comparison to P0562R2</h3>

<p>It is worth noting that <a href="https://wg21%2elink/p0562r2">[P0562R2]</a> did not propose trailing commas
in function and template parameters
with the following rationale:
</p>
<blockquote>
<p>Function and template parameters do not allow a final terminating comma,
but these do not  trouble me in practice.
(Arguably any function or template with enough parameters to be much 
of a maintenance issue seems like it is ripe for refactoring.)
This paper does not propose changing function or template parameters.
</p></blockquote>

<p>Note that <a href="https://wg21%2elink/p0562r2">[P0562R2]</a> argues that additional trailing commas for <g-term>mem-initializer-list</g-term>s
make "maintenance" easier.
Maintenance equally motivates trailing commas in function parameter lists.
However, <a href="https://wg21%2elink/p0562r2">[P0562R2]</a> holds function parameter lists to a double standard
where if you maintain such lists,
they are "ripe for refactoring" anyway.
</p>
<p>This position is hypocritical, lacks reason,
and is out-of-touch with language development at large,
where trailing commas in function parameter lists have recently been added to
various programming languages (<a href=#trailing-commas-in-other-languages>§1.2. Trailing commas in other languages</a>).
In fact, developers write tremendously more function parameter lists and argument lists than
<g-term>mem-initializer-list</g-term>s,
so the former are more deserving of attention.
</p>
<h3 id=could-this-syntax-be-used-for-something-else><a class=para href=#could-this-syntax-be-used-for-something-else></a>3.5. Could this syntax be used for something else?</h3>

<p>The idea has been floated on some mailing lists to give empty list elements special meaning,
such as using a default argument:
</p>
<code-block><h- data-h=kw_type>void</h-> <h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>int</h-> <h- data-h=id>x</h-> <h- data-h=sym_op>=</h-> <h- data-h=num>0</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>y</h-> <h- data-h=sym_op>=</h-> <h- data-h=num>0</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->

<h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>1</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->    <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> OK, equivalent to f(0, 1)</h->
<h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=num>1</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->    <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> OK, equivalent to f(1, 0)</h->
<h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=num>1</h-><h- data-h=sym_punc>,</h-><h- data-h=num>1</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->   <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> error: third default argument requested, but only two parameters</h-></code-block>

<p>Personally, I consider this idea terrible because of how non-descriptive it is;
a user could even unintentionally perform such calls by making a typo '<code><h- data-h=sym_punc>,</h-><h- data-h=sym_punc>,</h-></code>'
somewhere in the argument list.
Using the syntax <code><h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=num>1</h-><h- data-h=sym_punc>,</h-><h- data-h=num>1</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-></code> to mean anything other than a function call
with two arguments and a trailing comma would be terribly confusing to developers
accustomed to trailing commas from other languages,
such as JavaScript or Kotlin developers (<a href=#trailing-commas-in-other-languages>§1.2. Trailing commas in other languages</a>).
</p>
<h3 id=addressing-criticisms><a class=para href=#addressing-criticisms></a>3.6. Addressing criticisms</h3>

<h4 id=aesthetic-objections><a class=para href=#aesthetic-objections></a>3.6.1. Aesthetic objections</h4>

<p>I have unofficially polled the idea of trailing commas on social media
prior to drafting this proposal,
and a surprising amount of people objected to the idea.
Note that this was a blind poll without explaining the purpose of the feature beforehand.
When asking opponents of the idea why they don't like it,
the answers revolved around aesthetics.
In one case literally
</p>
<blockquote>
<p>it looks ugly
</p></blockquote>

<p>Since trailing commas are foreign to both natural language and mathematical notation,
I can sympathize with this position.
However, we must keep two things in mind:
</p>
<ul>
  <li>
    Aesthetic perception is heavily influenced by familiarity.
    A Python developer likely perceives C++' use of special characters in
    <code><h- data-h=sym_par>(</h-><h- data-h=sym_op>!</h-><h- data-h=id>x</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=id>y</h-><h- data-h=sym_par>)</h-></code> or <code><h- data-h=kw_type>int</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-><h- data-h=sym_op>::</h-><h- data-h=sym_op>*</h-><h- data-h=sym_par>)</h-></code> as "ugly".
    In practice, it is easy to get used to trailing commas.
    Since they are intended for multi-line scenarios,
    there is a fair amount of distance between '<code><h- data-h=sym_punc>,</h-></code>' and e.g. <code><h- data-h=sym_op>&gt;</h-></code> anyway.
  </li>
  <li>
    The job of WG21 is to standardize a programming language used by software engineers.
    Trailing commas have clear technical benefits laid out in <a href=#motivation>§2. Motivation</a>,
    and clear technical benefits should always take precedence over matters of personal taste.
    If we had gotten hung up over <code><h- data-h=sym_op>^^</h-></code> and <code><h- data-h=sym_sqr>[</h-><h- data-h=sym_op>::</h-><h- data-h=sym_sqr>]</h-></code> "looking ugly",
    C++26 reflections would have died.
  </li>
</ul>

<h4 id=concerns-over-c-compatibility><a class=para href=#concerns-over-c-compatibility></a>3.6.2. Concerns over C compatibility</h4>

<p>Some concerns have been raised regarding the fact that only C++ but not C
would support the use of trailing commas.
This was alleged to make writing common C and C++ code harder.
</p>
<p>However, the use of trailing commas is entirely optional,
so this claim is untrue.
It is not a stated design goal of C++ to make every possible line of C++ code valid C as well.
Instead, we maintain a common subset that is both valid C and valid C++.
If a developer wants to write C/C++-interoperable code,
they can simply not use trailing commas.
</p>
<p>Furthermore, I intend to follow this proposal up with a WG14 counterpart
if it finds consensus.
For the sake of C++ compatibility,
it is plausible that WG14 would adopt the syntax as well;
this has been done with numerous features before.
</p>
<h4 id=making-previously-ill-formed-code-valid><a class=para href=#making-previously-ill-formed-code-valid></a>3.6.3. Making previously ill-formed code valid</h4>

<p>Some people consider it a benefit that <code><h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-></code> is currently not allowed,
which may catch mistakes in some scenarios:
</p>
<blockquote>
<p>Maybe I was typing, distracted, and forgot my last argument?
Maybe a macro expanded badly?
</p></blockquote>

<p>The problem with this line of reasoning is that there are infinite things
that a developer may forget to type
and infinite ways in which macros can expand into something unintended.
Trailing commas are not particularly inviting to mistakes.
</p>
<p>It is also important to keep one of C++'s language design rules in mind
(see Design and Evolution of C++ — 4.3 Design Support Rules):
</p>
<blockquote>
<p>It is more important to allow a useful feature than to prevent every misuse.
</p></blockquote>

<p>The usefulness of trailing commas clearly outweighs the benefits
from this unlikely scenario where a mistake is caught.
Making obvious mistakes such as forgetting arguments likely results in a compiler error anyway,
with or without comma,
unless that forgotten argument has a default argument or an overload with fewer parameters exists.
</p>
<h4 id=semantic-inconsistencies-with-macros><a class=para href=#semantic-inconsistencies-with-macros></a>3.6.4. Semantic inconsistencies with macros</h4>

<p>With the proposed syntax in function calls,
<code><h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-></code> would be valid for both regular functions and for function-style macros.
Previously, it would have only been valid if <code><h- data-h=id>f</h-></code> is a function-style macro,
but the trailing comma would mean that we are passing two arguments, one of which is empty.
</p>
<p>This does result in a bit of surprising behavior for non-variadic cases:
</p><code-block><h- data-h=kw_type>void</h-> <h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=mac>#define F(x)</h->

<h- data-h=id>f</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->    <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>OK</h-></f-serif>
<h- data-h=mac>F</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->    <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>error: two arguments provided, but only one parameter</h-></f-serif></code-block>

<p>This inconsistency cannot be changed without altering the semantics of the preprocessor,
so it is here to stay.
However, it also seems largely inconsequential.
Users who are uncertain about whether <code><h- data-h=id>f</h-></code> is a macro can choose
not to use a trailing comma; it is entirely optional.
Furthermore, trailing commas in variadic macros "just work":
</p>
<code-block><h- data-h=mac>#define M(...) f(__VA_ARGS__)</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>looks like four comma-separated macro arguments (last is empty), but three function arguments</h-></f-serif>
<h- data-h=mac>M</h-><h- data-h=sym_par>(</h-><h- data-h=num>0</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>1</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>2</h-><h- data-h=sym_punc>,</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<h4 id=multiple-ways-to-do-the-same-thing><a class=para href=#multiple-ways-to-do-the-same-thing></a>3.6.5. Multiple ways to do the same thing</h4>

<p>A common and generally good rule of thumb in programming language design is:
</p>
<blockquote>
<p>Don't introduce multiple ways to do the same thing.
</p></blockquote>

<p>It could be argued that we can already spell parameter lists without a trailing comma,
so it is bad to add a second way.
However, this rule is not universally and innately true;
it is important to understand why one may follow it:
</p>
<ul>
  <li>
    Multiple ways of doing the same thing makes a language harder to teach.
  </li>
  <li>
    If we can already do the same thing a different way, no value is added to the language.
  </li>
</ul>

<p>The first motivation hardly applies because C++ already supports trailing commas in some lists.
One could argue the language becomes <em>more</em> teachable by fixing this inconsistency
and permitting it in all lists.
Even if that argument is not accepted,
the teaching effort for an optional punctuation character is microscopic.
</p>
<p>Secondly, <a href=#motivation>§2. Motivation</a> lays out numerous ways in which trailing commas
add value to the language.
It would be hard to argue that <code><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> line comments</h-></code> add no value to the language
because <code><h- data-h=cmt_dlim>/*</h-><h- data-h=cmt> block comments </h-><h- data-h=cmt_dlim>*/</h-></code> exist,
or that <code><h- data-h=num>1</h-><h- data-h=num_deco>s</h-></code> adds no value because <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>chrono</h-><h- data-h=sym_op>::</h-><h- data-h=id>seconds</h-><h- data-h=sym_par>(</h-><h- data-h=num>1</h-><h- data-h=sym_par>)</h-></code> exists.
It is fine to have multiple spellings of the same feature
when there are clear technical benefits to both spellings.
There are no hard rules in language design, only trade-offs and rules of thumb.
</p>
<h2 id=implementation-experience><a class=para href=#implementation-experience></a>4. Implementation experience</h2>

<p>None.
</p>
<h2 id=impact-on-existing-code><a class=para href=#impact-on-existing-code></a>5. Impact on existing code</h2>

<p>The proposal does not alter the meaning of any existing code;
it only makes previously ill-formed code valid.
</p>
<h2 id=wording><a class=para href=#wording></a>6. Wording</h2>

<p>In <a href=https://eel.is/c++draft/expr.prim.lambda.capture>[expr.prim.lambda.capture]</a>,
change the grammar as follows:
</p>
<style>
  .grammar {
    margin-left: 0;
  }
</style>

<diff-block>
<dl class=grammar>
  <dt><g-term>lambda-capture</g-term>:</dt>
  <dd>capture-default <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd>capture-list <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd>capture-default <code><h- data-h=sym_punc>,</h-></code> capture-list <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
</dl>
</diff-block>

<p>In <a href=https://eel.is/c++draft/dcl.pre#1>[dcl.pre] paragraph 1</a>,
change the grammar as follows:
</p>
<diff-block>
<dl class=grammar>
  <dt><g-term>sb-identifier-list</g-term>:</dt>
  <dd>sb-identifier <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd><del>sb-identifier-list <code><h- data-h=sym_punc>,</h-></code></del> sb-identifier <ins><code><h- data-h=sym_punc>,</h-></code> sb-identifier-list</ins></dd>
</dl>
</diff-block>

<p>In <a href=https://eel.is/c++draft/dcl.fct#2>[dcl.fct] paragraph 2</a>,
change the grammar as follows:
</p>
<diff-block>
<dl class=grammar>
  <dt><g-term>parameter-declaration-clause</g-term>:</dt>
  <dd><code><h- data-h=sym_op>...</h-></code></dd>
  <dd>parameter-declaration-list<sub class=opt>opt</sub></dd>
  <dd>parameter-declaration-list <code><h- data-h=sym_punc>,</h-></code> <code><h- data-h=sym_op>...</h-></code><ins><sub class=opt>opt</sub></ins></dd>
  <dd>parameter-declaration-list <code><h- data-h=sym_op>...</h-></code></dd>
</dl>
</diff-block>

<p>In <a href=https://eel.is/c++draft/dcl.init.general#1>[dcl.init.general] paragraph 1</a>,
change the grammar as follows:
</p>
<diff-block>
<p>[…]</p>

<dl class=grammar>
  <dt><g-term>braced-init-list</g-term>:</dt>
  <dd><tt->{</tt-> initializer-list <del><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></del> <tt->}</tt-></dd>
  <dd><tt->{</tt-> designated-initializer-list <del><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></del> <tt->}</tt-></dd>
  <dd><tt->{</tt-> <tt->}</tt-></dd>
</dl>

<dl class=grammar>
  <dt><g-term>initializer-list</g-term>:</dt>
  <dd>initializer-clause <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd><del>initializer-list <code><h- data-h=sym_punc>,</h-></code></del> initializer-clause <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code> initializer-list</ins></dd>
</dl>

<dl class=grammar>
  <dt><g-term>designated-initializer-list</g-term>:</dt>
  <dd>designated-initializer-clause <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd><del>designated-initializer-list <code><h- data-h=sym_punc>,</h-></code></del> designated-initializer-clause <ins><code><h- data-h=sym_punc>,</h-></code> designated-initializer-list</ins></dd>
</dl>

<p>[…]
</p></diff-block>

<p>In <a href=https://eel.is/c++draft/dcl.attr.grammar#1>[dcl.attr.grammar] paragraph 1</a>,
change the grammar as follows:
</p>
<diff-block>
<dl class=grammar>
  <dt><g-term>annotation-list</g-term>:</dt>
  <dd>annotation <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd><del>annotation-list <code><h- data-h=sym_punc>,</h-></code></del> annotation <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code> annotation-list</ins></dd>
</dl>
</diff-block>

<p>In <a href=https://eel.is/c++draft/temp.pre#1>[temp.pre] paragraph 1</a>,
change the grammar as follows:
</p>
<diff-block>
<dl class=grammar>
  <dt><g-term>template-parameter-list</g-term>:</dt>
  <dd>template-parameter <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd><del>template-parameter-list <code><h- data-h=sym_punc>,</h-></code></del> template-parameter <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code> template-parameter-list</ins></dd>
</dl>
</diff-block>

<p>In <a href=https://eel.is/c++draft/temp.names#1>[temp.names] paragraph 1</a>,
change the grammar as follows:
</p>
<diff-block>
<dl class=grammar>
  <dt><g-term>template-argument-list</g-term>:</dt>
  <dd>template-argument <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code><sub class=opt>opt</sub></ins></dd>
  <dd><del>template-argument-list <code><h- data-h=sym_punc>,</h-></code></del> template-argument <code><h- data-h=sym_op>...</h-></code><sub class=opt>opt</sub> <ins><code><h- data-h=sym_punc>,</h-></code> template-argument-list</ins></dd>
</dl>
</diff-block>

<p>If the proposed resolution of <a href="https://github%2ecom/cplusplus/CWG/issues/754">[CWGGithub754]</a> at the time of writing has been applied,
revert the change as follows:
</p>
<diff-block>
<dl class=grammar>
  <dt><g-term>expansion-init-list</g-term>:</dt>
  <dd><tt->{</tt-> expression-list <del><code><h- data-h=sym_punc>,</h-></code></del><sub class=opt>opt</sub> <tt->}</tt-></dd>
  <dd><del><tt->{</tt-> <tt->}</tt-></del></dd>
</dl> 
</diff-block>

<h2 id=references><a class=para href=#references></a>7. References</h2>




<div class=bib><div id=bib-item-N5014 class=bib-item>
<a href="https://wg21%2elink/n5014">[N5014]</a>
<span class=bib-author>Thomas Köppe.</span>
<span class=bib-title>Working Draft, Programming Languages — C++</span>
<span class=bib-date>2025-08-05</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2025/n5014%2epdf" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5014.pdf</a></div><div id=bib-item-P0562R2 class=bib-item>
<a href="https://wg21%2elink/p0562r2">[P0562R2]</a>
<span class=bib-author>Alan Talbot.</span>
<span class=bib-title>Trailing Commas in Base-clauses and Ctor-initializers</span>
<span class=bib-date>2024-04-15</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2024/p0562r2%2epdf" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0562r2.pdf</a></div><div id=bib-item-P3312R1 class=bib-item>
<a href="https://wg21%2elink/p3312r1">[P3312R1]</a>
<span class=bib-author>Bengt Gustafsson.</span>
<span class=bib-title>Overload Set Types</span>
<span class=bib-date>2025-04-16</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2025/p3312r1%2epdf" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3312r1.pdf</a></div><div id=bib-item-CWGGithub754 class=bib-item>
<a href="https://github%2ecom/cplusplus/CWG/issues/754">[CWGGithub754]</a>
<span class=bib-author>Jan Schultke.</span>
<span class=bib-title>[stmt.expand] Trailing commas in an expansion-init-list should be permitted</span>
<span class=bib-date>2025-08-24</span>
<a href="https://github%2ecom/cplusplus/CWG/issues/754" class=bib-link>https://github.com/cplusplus/CWG/issues/754</a></div><div id=bib-item-P0562R2ReflectorDiscussion class=bib-item>
<a href="https://lists%2eisocpp%2eorg/core/2024/06/15961%2ephp">[P0562R2ReflectorDiscussion]</a>
<span class=bib-title>[isocpp-core] P0562R2 -- how is a compiler intended to find the end of a constructor definition?</span>
<span class=bib-date>2024-06-27</span>
<a href="https://lists%2eisocpp%2eorg/core/2024/06/15961%2ephp" class=bib-link>https://lists.isocpp.org/core/2024/06/15961.php</a></div><div id=bib-item-CoreReflectorDiscussion class=bib-item>
<a href="https://lists%2eisocpp%2eorg/core/2025/08/18487%2ephp">[CoreReflectorDiscussion]</a>
<span class=bib-title>[isocpp-core] P3776R0 Review of grammar changes
  date = 2025-08-25</span>
<a href="https://lists%2eisocpp%2eorg/core/2025/08/18487%2ephp" class=bib-link>https://lists.isocpp.org/core/2025/08/18487.php</a></div><div id=bib-item-RustTrailingCommas class=bib-item>
<a href="https://doc%2erust-lang%2eorg/style-guide/#trailing-commas">[RustTrailingCommas]</a>
<span class=bib-title>Rust Style Guide — Trailing commas</span>
<a href="https://doc%2erust-lang%2eorg/style-guide/#trailing-commas" class=bib-link>https://doc.rust-lang.org/style-guide/#trailing-commas</a></div><div id=bib-item-KotlinTrailingCommas class=bib-item>
<a href="https://kotlinlang%2eorg/docs/whatsnew14%2ehtml#trailing-comma">[KotlinTrailingCommas]</a>
<span class=bib-title>What's new in Kotlin 1.4.0 — Trailing comma</span>
<span class=bib-date>2020-08-17</span>
<a href="https://kotlinlang%2eorg/docs/whatsnew14%2ehtml#trailing-comma" class=bib-link>https://kotlinlang.org/docs/whatsnew14.html#trailing-comma</a></div><div id=bib-item-ECMAScriptTrailingCommas class=bib-item>
<a href="https://github%2ecom/tc39/proposal-trailing-function-commas">[ECMAScriptTrailingCommas]</a>
<span class=bib-title>Proposal to allow trailing commas in function parameter lists</span>
<a href="https://github%2ecom/tc39/proposal-trailing-function-commas" class=bib-link>https://github.com/tc39/proposal-trailing-function-commas</a></div><div id=bib-item-TypeScriptTrailingCommas class=bib-item>
<a href="https://www%2etypescriptlang%2eorg/docs/handbook/release-notes/typescript-2-0%2ehtml#trailing-commas-in-function-parameter-and-argument-lists">[TypeScriptTrailingCommas]</a>
<span class=bib-title>TypeScript 2.0 — Trailing commas in function parameter and argument lists</span>
<a href="https://www%2etypescriptlang%2eorg/docs/handbook/release-notes/typescript-2-0%2ehtml#trailing-commas-in-function-parameter-and-argument-lists" class=bib-link>https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#trailing-commas-in-function-parameter-and-argument-lists</a></div><div id=bib-item-CSharpTrailingCommas class=bib-item>
<a href="https://github%2ecom/dotnet/csharplang/issues/1246">[CSharpTrailingCommas]</a>
<span class=bib-title>Proposal: Allow trailing comma in tuples &amp; argument lists</span>
<a href="https://github%2ecom/dotnet/csharplang/issues/1246" class=bib-link>https://github.com/dotnet/csharplang/issues/1246</a></div><div id=bib-item-SwiftTrailingCommas class=bib-item>
<a href="https://forums%2eswift%2eorg/t/allow-trailing-commas-in-parameter-lists/68549/29">[SwiftTrailingCommas]</a>
<span class=bib-title>Allow trailing commas in parameter lists</span>
<a href="https://forums%2eswift%2eorg/t/allow-trailing-commas-in-parameter-lists/68549/29" class=bib-link>https://forums.swift.org/t/allow-trailing-commas-in-parameter-lists/68549/29</a></div><div id=bib-item-RedditTrailingCommas class=bib-item>
<a href="https://www%2ereddit%2ecom/r/ProgrammingLanguages/comments/1amsalm/does_your_language_support_trailing_commas/">[RedditTrailingCommas]</a>
<span class=bib-title>Does your language support trailing commas?</span>
<a href="https://www%2ereddit%2ecom/r/ProgrammingLanguages/comments/1amsalm/does_your_language_support_trailing_commas/" class=bib-link>https://www.reddit.com/r/ProgrammingLanguages/comments/1amsalm/does_your_language_support_trailing_commas/</a></div><div id=bib-item-OldNewThing class=bib-item>
<a href="https://devblogs%2emicrosoft%2ecom/oldnewthing/20240209-00/?p=109379">[OldNewThing]</a>
<span class=bib-author>Raymond Chen.</span>
<span class=bib-title>On the virtues of the trailing comma</span>
<span class=bib-date>2024-02-09</span>
<a href="https://devblogs%2emicrosoft%2ecom/oldnewthing/20240209-00/?p=109379" class=bib-link>https://devblogs.microsoft.com/oldnewthing/20240209-00/?p=109379</a></div></div>
</main></body>
</html>
