<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
        <title>
            Allowing any unsigned integral type as parameter type for literal operators
        </title>
        <style type="text/css">
            ins { text-decoration: none; font-weight: bold; background-color: #A0FFA0; }
            del { text-decoration: line-through; background-color: #FFA0A0; }
        </style>
    </head>

    <body>
        <article>
            <h1>
                Allowing any unsigned integral type as parameter type for literal operators
            </h1>

            <p>
                <em>
                    Author: Michał Dominiak, <a href="mailto:griwes@griwes.info">griwes@griwes.info</a>
                </em>
                <br />
                <em>
                    Document number: P0345R0
                </em>
                <br />
                <em>
                    Date: 2016-05-25
                </em>
            </p>

            <h2>
                Introduction
            </h2>

            <p>
                User-defined literals are a great tool for shortening code that would otherwise need to be overly verbose,
                but since the first proposal, they lacked one feature that would make writing code even simpler - supporting
                arbitrary unsigned types as arguments for <code>operator""</code>. Consider the following code:
            </p>

            <pre>
    constexpr std::uint8_t operator "" _foo(unsigned long long value)
    {
        return value;
    }

    int main()
    {
        auto foo = 1024_foo;    // this compiles with no warnings, even though it overflows, whereas this:
        char bar = 1024;        // warns about changing the value
    }
            </pre>

            <p>
                It should be obvious that the first should also produce a diagnostic, since it might be a result of a
                simple programming mistake. There is also another problem, which appears to be far less important, but
                still exists. Consider the following platform specific code for a platform, where <code>std::uint64_t</code>
                is the biggest unsigned integer type:
            </p>

            <pre>
    constexpr std::uint64_t operator "" _bar(std::uint64_t value)
    {
        // ...
    }
            </pre>

            <p>
                results in an error in both GCC and Clang, because they use <code>unsigned long</code>, not <code>unsigned
                long long</code> for <code>std::uint64_t</code>, at least on Linux. This is an environment-specific problem,
                but the Standard should provide a way to overcome it in a portable way.
            </p>

            <h2>
                Proposed solution
            </h2>

            <p>
                The proposed solution is as follows:
            </p>

            <ol>
                <li>
                    Allow any unsigned type as an argument for <code>operator ""</code>, not <code>unsigned long long</code>
                    only.
                </li>

                <li>
                    Make narrowing in case of user defined literals ill-formed.
                </li>
            </ol>

            <p>
                An additional feature gained with 1) and 2) is allowing to limit the range of values used in a user-defined literal.
            </p>

            <p>
                <strong>Note</strong>: this proposal doesn't propose <code>operator ""</code> overloading for unsigned
                integral types. Allowing such overloading would create ambiguities; it is not desirable.
            </p>

            <h2>
                Proposed wording changes
            </h2>

            <p>
                Change in 13.5.8 over.literal paragraph 3:

                <blockquote>
                    The declaration of a literal operator shall have a <em>parameter-declaration-clause</em> equivalent
                    to one of the following:
                    <ul>
                        <li><code>const char*</code></li>
                        <li><ins><code>unsigned char</code></ins></li>
                        <li><ins><code>unsigned short int</code></ins></li>
                        <li><ins><code>unsigned int</code></ins></li>
                        <li><ins><code>unsigned long int</code></ins></li>
                        <li><code>unsigned long long int</code></li>
                        <li><ins>an extended unsigned integer type ([basic.fundamental].3)</ins></li>
                        <li>...</li>
                    </ul>
                </blockquote>

                Add two new paragraphs before 13.5.8 over.literal paragraph 5:

                <blockquote>
                    <ins>
                        Literal operator overloading for unsigned integral types is not supported. If there exist two
                        or more literal operator declarations with the same literal suffix identifier with a single
                        parameter, but of different unsigned integral types, the program is ill-formed.

                        <br />
                        <br />

                        If a narrowing conversion would happen when a literal operator with a single parameter of an
                        unsigned integral type is invoked implicitly through user-defined literal, the program is
                        ill-formed.
                    </ins>
                </blockquote>

                Change in 13.5.8 over.literal paragraph 8:

                <blockquote>
                    <pre>
    template &lt;char...&gt; int operator "" _j(const char*); // error: invalid parameter-declaration-clause
<ins>    std::uint8_t operator "" _k(std::uint8_t);
    auto l = 256_k;                                     // error: integer constant is too large for its type
    std::uint16_t operator "" _k(std::uint16_t);        // error: literal operator overloading is not supported
</ins>
                </blockquote>
        </article>
    </body>
</html>
