Inlining

Function inlining

Attaching the BRONTO_INLINE() attribute to a function indicates that calls to the function should be replaced with the expression in the function's body.1

class Container {
 public:
  bool empty() const { ... }
  ...
};

// Deprecated. Use the `empty` member function instead.
BRONTO_INLINE()
bool IsEmpty(const Container& c) {
  return c.empty();
}

Requirements

For a function to be inlined, it must either

  • have an empty body,
  • have a single return statement (and no other statements), or
  • have a single statement which is an expression.

Constructor inlining

Attaching the BRONTO_INLINE() attribute to a delegating constructor indicates that constructions invoking that constructor should be replaced with the delegated-to constructor. This should feel similar to function inlining, as constructors are very nearly functions.

class Interval {
 public:
  BRONTO_INLINE()
  Interval(double lower, double upper)
    : Interval(make(lower, upper).value()) {}

  static std::expected<Interval, InvalidIntervalError> make(
      double lower, double upper) {
    if (lower > upper) { return std::nullopt; }
    Interval i;
    i.lower_ = lower;
    i.upper_ = upper;
    return i;
  }
  ...
};

Requirements

For a constructor to be inlined, it must delegate to another constructor of the same type and otherwise have an empty body.

Type inlining

Attaching the BRONTO_INLINE() to a type alias indicates that uses of the alias should be replaced by the aliased type. This should also feel similar to function inlining, but at the type-level, rather than expression-level.

template <typename T, typename U>
using PtrPair BRONTO_INLINE() = std::pair<T*, U*>;

Requirements

For a type alias to be inlined it must not have variadic or non-type template parameters.

Enumerator inlining

Attaching the BRONTO_INLINE() attribute to an enumerator indicates that uses of that enumerator should be replaced with its initializing expression. This should feel similar to function inlining, but at the expression level for named constants.

enum Color {
  Red,
  Green,
  Cerulean,
  Blue BRONTO_INLINE() = Cerulean
};

You can see an example live on Compiler Explorer.

Requirements

For an enumerator to be inlined, it must have an explicit initializer. Enumerators dependent on template parameters are not currently supported.

Namespace inlining

Attaching the BRONTO_INLINE() to a using directive indicates that any symbol found through the using directive should be qualified with the named namespace.

For example, one could add std qualifications via

BRONTO_INLINE() using namespace std;

or rename a namespace with

namespace new_namespace {
BRONTO_INLINE() using namespace old_namespace;
}  // new_namespace

Requirements

There are no requirements on using directives. Any using directive may have BRONTO_INLINE() applied to it.

Macro inlining

Defining a macro whose initial tokens are BRONTO_INLINE_MACRO() indicates that the subsequent macro body should be directly inserted into expansion sites. Only a single level of expansion will be inlined; any macros present in the inlined macro body will be written as-is, rather than recursively expanded. Macros will only be inlined if they are written directly in the source text and not if they are encountered during expansion of another macro.

#define IS_EOF(ch) BRONTO_INLINE_MACRO() (ch) == EOF

Requirements

There are no requirements on macro inlining. Any macro definition may have BRONTO_INLINE_MACRO() applied to it.

Footnotes

  1. Abseil's ABSL_REFACTOR_INLINE annotation is also supported as an alias for BRONTO_INLINE. See it in action on compiler explorer.

On this page