Skip to main content

C++ named requirements:LiteralType (since C++11)

Specifies that a type is a literal type. Literal types are the types of constexpr variables and they can be constructed, manipulated, and returned from constexpr functions.

Note: the standard doesn't define a named requirement with this name. This is a type category defined by the core language. It is included here as a named requirement only for consistency.

Requirements

A literal type is any of the following:

  • possibly cv-qualified void (so that constexpr functions can return void); (since C++14)
  • scalar type;
  • refrence type;
  • an array of literal type;
  • possibly cv-qualified class type that has all of the following properties:
    • has a trivial (until C++20) constexpr (since C++20) destructor,
    • is one of
    • a non-union aggregate type, and each of its anonymous union members
      • has no variant members, or
      • has at least one variant member of non-volatile literal type,
    • a type with at least one constexpr (possibly template) constructor that is not a copy or move constructor,

Notes

A type can be literal even if all of its constexpr constructors are deleted, inaccessible, or cannot participate in overload resolution.

struct A { constexpr A(int) = delete; char c; };    // A is a literal type
constexpr A v = std::bit_cast<A>('0'); // OK in C++20
// v has literal type and thus can be constexpr

Example

Literal type that extends string literals:

#include <cstddef>
#include <iostream>
#include <stdexcept>

class conststr // conststr is a literal type
{
const char* p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]) : p(a), sz(N - 1) {}

constexpr char operator[](std::size_t n) const
{
return n < sz ? p[n] : throw std::out_of_range("");
}

constexpr std::size_t size() const { return sz; }
};

constexpr std::size_t count_lower(conststr s)
{
std::size_t c{};
for (std::size_t n{}; n != s.size(); ++n)
if ('a' <= s[n] && s[n] <= 'z')
++c;
return c;
}

// An output function that requires a compile-time constant N, for testing
template<int N>
struct constN
{
constN() { std::cout << N << '\n'; }
};

int main()
{
std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
constN<count_lower("Hello, world!")>(); // the string literal is implicitly
// converted to conststr
}
Result
the number of lowercase letters in "Hello, world!" is 9

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DRApplied toBehavior as publishedCorrect behavior
CWG 1453C++11a literal class could have volatile data membersnot allowed
CWG 1951C++11 C++14it was unclear whether cv-qualified void (C++14) and class types (C++11) are literal typesthey are
CWG 2096C++11for a union type to be literal, all its non- static data members must be literalonly one non-static data member needs to be
CWG 2598C++11for a union type to be literal, it must have at least one non-static data memberit can have no non- static data member

C++ named requirements:LiteralType (since C++11)

Specifies that a type is a literal type. Literal types are the types of constexpr variables and they can be constructed, manipulated, and returned from constexpr functions.

Note: the standard doesn't define a named requirement with this name. This is a type category defined by the core language. It is included here as a named requirement only for consistency.

Requirements

A literal type is any of the following:

  • possibly cv-qualified void (so that constexpr functions can return void); (since C++14)
  • scalar type;
  • refrence type;
  • an array of literal type;
  • possibly cv-qualified class type that has all of the following properties:
    • has a trivial (until C++20) constexpr (since C++20) destructor,
    • is one of
    • a non-union aggregate type, and each of its anonymous union members
      • has no variant members, or
      • has at least one variant member of non-volatile literal type,
    • a type with at least one constexpr (possibly template) constructor that is not a copy or move constructor,

Notes

A type can be literal even if all of its constexpr constructors are deleted, inaccessible, or cannot participate in overload resolution.

struct A { constexpr A(int) = delete; char c; };    // A is a literal type
constexpr A v = std::bit_cast<A>('0'); // OK in C++20
// v has literal type and thus can be constexpr

Example

Literal type that extends string literals:

#include <cstddef>
#include <iostream>
#include <stdexcept>

class conststr // conststr is a literal type
{
const char* p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]) : p(a), sz(N - 1) {}

constexpr char operator[](std::size_t n) const
{
return n < sz ? p[n] : throw std::out_of_range("");
}

constexpr std::size_t size() const { return sz; }
};

constexpr std::size_t count_lower(conststr s)
{
std::size_t c{};
for (std::size_t n{}; n != s.size(); ++n)
if ('a' <= s[n] && s[n] <= 'z')
++c;
return c;
}

// An output function that requires a compile-time constant N, for testing
template<int N>
struct constN
{
constN() { std::cout << N << '\n'; }
};

int main()
{
std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
constN<count_lower("Hello, world!")>(); // the string literal is implicitly
// converted to conststr
}
Result
the number of lowercase letters in "Hello, world!" is 9

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DRApplied toBehavior as publishedCorrect behavior
CWG 1453C++11a literal class could have volatile data membersnot allowed
CWG 1951C++11 C++14it was unclear whether cv-qualified void (C++14) and class types (C++11) are literal typesthey are
CWG 2096C++11for a union type to be literal, all its non- static data members must be literalonly one non-static data member needs to be
CWG 2598C++11for a union type to be literal, it must have at least one non-static data memberit can have no non- static data member