Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An inline namespace is a namespace declared with the inline specifier, which instructs the compiler to treat its members as if they belong directly to its enclosing namespace. This mechanism allows the members of the nested inline namespace to participate in name lookup, overload resolution, and template specialization exactly as if they were declared in the parent namespace, while still maintaining a distinct declarative region.

Syntax

Traditional Syntax (C++11 and later)
namespace enclosing_namespace {
    inline namespace inline_namespace {
        class MyClass {};
        void myFunction();
    }
}
Concise Nested Syntax (C++20 and later)
namespace enclosing_namespace::inline inline_namespace {
    class MyClass {};
    void myFunction();
}

Primary Motivation: API and ABI Versioning

The canonical motivation for inline namespaces is managing API and ABI versioning. Inline namespaces allow multiple versions of a library to coexist within the same binary. By placing different implementations into separate nested namespaces (e.g., V1 and V2), the inline keyword can be used to designate the default version exposed to the parent namespace. Clients calling the parent namespace automatically resolve to the inline version, while older or non-default versions remain fully accessible via explicit qualification.
namespace Library {
    namespace V1 {
        void process(); // Legacy ABI
    }
    
    inline namespace V2 {
        void process(); // Current default ABI
    }
}

void clientCode() {
    Library::process();     // Implicitly resolves to Library::V2::process()
    Library::V1::process(); // Explicitly calls the older version
}

Core Mechanics

1. Name Visibility and Lookup Members of an inline namespace are made visible in the enclosing namespace. They can be accessed using either the fully qualified name or the enclosing namespace’s scope resolution.
namespace Core {
    inline namespace V1 {
        void execute();
    }
}

void run() {
    // Both calls resolve to the exact same function
    Core::V1::execute(); 
    Core::execute();     // Implicitly resolves to Core::V1::execute
}
2. Argument-Dependent Lookup (ADL) When a function call is resolved via ADL, the compiler searches the namespaces associated with the function arguments. If an argument’s type is defined within an inline namespace, both the inline namespace and its enclosing namespace are added to the associated namespaces set. Conversely, if the type is in the enclosing namespace, the inline namespace is also searched. 3. Template Specialization A primary template declared inside an inline namespace can be explicitly specialized or partially specialized in the enclosing namespace without needing to qualify the nested namespace’s name. Standard C++ allows specialization in an enclosing namespace for non-inline nested namespaces, but it requires the template name to be qualified with the nested namespace (e.g., template <> class Impl::Processor<int> {};). Inline namespaces allow the specialization to use the unqualified name directly within the enclosing scope.
namespace Library {
    inline namespace Impl {
        template <typename T>
        class Processor {};
    }
    
    // Valid: Specializing the template without qualifying 'Impl::'
    template <>
    class Processor<int> {}; 
}
4. Transitivity The inline property is transitive. If an inline namespace is nested within another inline namespace, the members of the innermost namespace are elevated to the nearest non-inline enclosing namespace.
namespace Outer {
    inline namespace Inner1 {
        inline namespace Inner2 {
            void process();
        }
    }
}

int main() {
    // Directly resolves to Outer::Inner1::Inner2::process()
    Outer::process(); 
    return 0;
}
5. Multiple Declarations and Translation Unit Consistency A namespace can be opened and closed multiple times. Within a single translation unit, the inline specifier must be present on the first declaration (the original namespace definition) of that namespace. Subsequent extension declarations of the same namespace within that same translation unit do not require the inline keyword, as the inline property is implicitly retained. Crucially, this property must be strictly consistent across the entire program. According to the C++ standard ([namespace.def.general]), if the inline specifier is present on the first definition of a namespace in a translation unit, it shall be present on the first definition of that namespace in every translation unit in which it is defined. Failing to declare a namespace as inline consistently across all translation units renders the program ill-formed, no diagnostic required (IFNDR).
// Translation Unit A
namespace App {
    inline namespace Core { // First declaration in this TU requires 'inline'
        int x;
    }
    
    namespace Core {        // 'inline' is implicit here
        int y;
    }
}

// Translation Unit B
namespace App {
    inline namespace Core { // MUST be inline here as well on first definition
        int z;
    }
}
Master C++ with Deep Grasping Methodology!Learn More