Document number D1819R0
Date 2019-07-16
Reply-to Vittorio Romeo <>
Audience Evolution Working Group Incubator (EWGI)
Project ISO JTC1/SC22/WG21: Programming Language C++

Interpolated literals

Abstract

This paper proposes the addition of interpolated literals to the C++ language, a new form of string literals that can contain and retain arbitrary expressions. Interpolated literals provide a terse and readable syntax to generate strings embedding results of C++ expressions in a human-readable manner. The proposed feature is completely decoupled from any existing Standard Library facility, and provides a customization point to allow both Standard Library and user-defined types to visit the elements of an interpolated literal.

Overview

One of the most common operations in any C++ code base is printing the value of a variable or the result of an expression alongside a human-readable message. Older techniques to achieve that goal, such as <iostream> and printf, have major drawbacks including verbosity and lack of type-safety. The upcoming <format> header addresses some of those problems, but still requires the user to pass the expressions that need to be printed separately from the body of the literal1, and the formatting happens at run-time rather than compile-time.

This paper proposes a flexible language feature that does not intend to compete with <format> - instead, it intends to complete the set of C++ formatting tools available for users by providing a compile-time-friendly mechanism to process expressions embedded in string literal.

Execution i18n Expressions
<format> Run-time Supported Passed as arguments
Interpolated literals Compile-time Not supported Embedded in literal

In A Nutshell

Here’s how interpolated literals can be used to print a variable to stdout:

int port = 27015;
std::cout << f"Connecting on port {port}...\n";
//            ^~~~~~~~~~~~~~~~~~~ ^~~~~ ^~~
//            literal piece       |     |
//                                expression piece
//                                      |
//                                      literal piece

Arbitrary expressions are supported as part of the interpolated literal:

int get_result() { return 42; }
std::cout << f"The result is {get_result()}\n";

Syntax

Semantics

Examples

Consuming an interpolated literal

Consumers of interpolated literals (e.g. std::ostream) can provide operator overloads accepting any object that satisfies InterpolatedLiteral. Note that the language feature is completely decoupled from any existing Standard Library facility. It is possible to use it with <iostream>, <string>, or any other user-defined type by simply defining appropriate overloads accepting InterpolatedLiteral.

Examples

Motivating examples

The main purpose of this feature is to allow users to conveniently print human-readable strings containing expressions.

Debugging and logging

Interpolated literals are the easiest and tersest way to provide logs or debug print statements.

Automated coloring

If the feature is defined to automatically tag arguments as either string literal pieces or embedded expressions, it is possible to automatically color the embedded expressions when printing to a console. This can also be achieved by inspecting the type of the arguments passed to the higher-order function, at the cost of not being able to differentiate between string literal pieces and embedded expressions that evaluate to string literals. E.g.

struct pretty_cout { /* ... */ };

pretty_cout& operator+=(pretty_cout& os, const InterpolatedLiteral auto& il)
{
    il([&os](const auto&... xs)
    {
        ([&](const auto& x)
        {
            if constexpr (is_string_literal(x))
            {
                os << x;
            }
            else if constexpr (is_embedded_expression(x))
            {
                os << ansi_color::green << x << ansi_color::white;
            }
        }(xs), ...);
    });

    return os;
}

constexpr std::string_view name{"Bob"};
pretty_cout{} << f"Hello world! My name is {name}!\n";
    // "Bob" gets automatically colored in green in the console output.

FAQ

TODO

This proposal is just a draft to see EWGI likes the approach. If there is enough positive feedback, these are some points to think about:


  1. I.e. the expressions to format cannot be embedded directly in the literal. {} placeholders must instead be used, and the expressions have to be passed as arguments to the format call separately. See the FAQ section for more details.