C++ Logo

std-proposals

Advanced search

[std-proposals] Do we still need literal types?

From: Mital Ashok <mital_at_[hidden]>
Date: Fri, 19 Jan 2024 13:36:35 +0000
There are exactly 17 paragraphs in the standard referring to literal types:

 * https://wg21.link/basic.def.odr#14.5.1.1
 * https://wg21.link/basic.types.general#10
 * https://wg21.link/expr.prim.lambda.closure#example-3
 * https://wg21.link/expr.prim.lambda.capture#12
 * https://wg21.link/expr.const#2.2
 * https://wg21.link/expr.const#4.7
 * https://wg21.link/expr.const#5.9.2
 * https://wg21.link/expr.const#5.16
 * https://wg21.link/expr.const#7
 * https://wg21.link/expr.const#12
 * https://wg21.link/dcl.constexpr#6
 * https://wg21.link/temp.param#7.3
 * https://wg21.link/zombie.names#1.25
 * https://wg21.link/zombie.names#1.26
 * https://wg21.link/concept.swappable#2.3.1
 * https://wg21.link/complex.numbers.general#2
 * https://wg21.link/diff.cpp17.depr#7

Some of these are just unnecessarily qualified as literal types.

For example, [concept.swappable] doesn't need to mention literal
types. If the type wasn't a literal type but all of `E1 =
std::move(E2); E2 = std::move(E1); T t1(std::move(E1)); T
t2(std::move(E2));` were constant expressions, what is the harm in
allowing it to be a constant expression?

Likewise for [expr.const]: If a type is not literal but is being used
in a way that would be a constant expression otherwise, why disallow
it?

I'm assuming the original rationale for literal types in C++11 was to
restrict it so much that compilers would be able to implement
constexpr functions. But nowadays the restrictions are so broad that
basically any type can be accepted. For example, this is a literal
type:

    struct Literal { constexpr LiteralType(int) = delete; };

And this is not:

    struct NotLiteral { constexpr NotLiteral(const NotLiteral&) = default; };
    constexpr NotLiteral f = f; // (The *only* reason this doesn't
work is that `NotLiteral` isn't a literal type)

This goes against the note given in its definition: "A literal type is
one for which it might be possible to create an object within a
constant expression.".

It also excludes extension types and is apparently difficult to get
right, because the following is accepted:

    struct ActuallyNotLiteral { ActuallyNotLiteral();
ActuallyNotLiteral(const ActuallyNotLiteral&); };
    union AccidentallyLiteral {
        ActuallyNotLiteral m;
        constexpr AccidentallyLiteral(int) = delete;
    };
    // AccidentallyLiteral is supposedly a literal type

because CWG2598's resolution now no longer asks for a variant member
to have a literal type if there is a constexpr constructor, where it
did with the prior wording.

I propose getting rid of "literal type" entirely. This involves nixing
[basic.types.general]p10 entirely and removing mentions to literal
types (e.g., [basic.def.odr]p(14.5.1.1) goes from "has the same
literal type" to "has the same type" and removing after ", except ..."
in [expr.const]p(2.2))

Received on 2024-01-19 13:37:11