Extending the namespace std

From cppreference.com
< cpp‎ | language
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Function declaration
Lambda function declaration
inline specifier
Exception specifications (until C++20)
noexcept specifier (C++11)
decltype (C++11)
auto (C++11)
alignas (C++11)
Storage duration specifiers
Alternative representations
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Attributes (C++11)
typedef declaration
Type alias declaration (C++11)
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Class-specific function properties
Special member functions

Adding declarations to std

It is undefined behavior to add declarations or definitions to namespace std or to any namespace nested within std, with a few exceptions noted below

#include <utility>
namespace std {
    // a function definition added to namespace std: undefined behavior
    pair<int, int> operator+(pair<int, int> a, pair<int, int> b) {
        return {a.first+b.first, a.second+b.second};

Adding template specializations

It is allowed to add template specializations for any standard library class (since C++20)template to the namespace std only if the declaration depends on at least one program-defined type and the specialization satisfies all requirements for the original template, except where such specializations are prohibited.

// Get the declaration of the primary std::hash template.
// We are not permitted to declare it ourselves.
// <typeindex> is guaranteed to provide such a declaration, 
// and is much cheaper to include than <functional>.
#include <typeindex> 
// Specialize std::hash so that MyType can be used as a key in 
// std::unordered_set and std::unordered_map
namespace std {
    template <> struct hash<MyType> {
      std::size_t operator()(const MyType& t) const { return t.hash(); }
  • It is undefined behavior to declare a full specialization of any member function of a standard library class template
  • It is undefined behavior to declare a full specialization of any member function template of a standard library class or class template
  • It is undefined behavior to declare a full or partial specialization of any member class template of a standard library class or class template.
  • It is undefined behavior to declare a full or partial specialization of any standard library variable template.
  • Specializing the template std::complex for any type other than float, double, and long double is unspecified.
  • Specializations of std::hash for program-defined types must satisfy Hash requirements.
  • Specializations of std::atomic must have a deleted copy constructor, a deleted copy assignment operator, and a constexpr value constructor.
  • Specializations of std::istreambuf_iterator must have a trivial copy constructor, a constexpr default constructor, and a trivial destructor.
(until C++17)

Explicit instantiation of templates

It is allowed to explicitly instantiate a class (since C++20)template defined in the standard library only if the declaration depends on the name of at least one program-defined type and the instantiation meets the standard library requirements for the original template.

Other restrictions

The namespace std may not be declared as an inline namespace.

Addressable functions

The behavior of a C++ program is unspecified (possibly ill-formed) if it explicitly or implicitly attempts to form a pointer, reference (for free functions and static member functions) or pointer-to-member (for non-static member functions) to the a standard library function or an instantiation of a standard library function template, unless it is designated an addressable function.

The only addressable functions in the standard library are I/O manipulators that are functions (or instantiations of function templates) taking a reference to a stream as their only argument, e.g. std::endl, std::boolalpha.

Following code was well-defined in C++17, but leads to unspecified behaviors and possibly fails to compile since C++20:

#include <cmath>
#include <memory>
int main()
    auto fptr0 = &std::betaf; // by unary operator&
    auto fptr1 = std::addressof(std::betal) // by std::addressof
    auto fptr2 = std::riemann_zetaf; // by function-to-pointer implicit conversion
    auto &fref = std::riemann_zetal; // forming a reference
    auto mfptr = &std::allocator<int>::allocate; // forming a pointer to member function
(since C++20)