It may seem tidy to add your new declarations to the std
or posix
namespaces, but doing so results in undefined behavior.
The C++14 Standard, [namespace.std] (ISO/IEC 14882-2014 §17.6.4.2.1), paragraphs 1 and 2 states:
- The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std
unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration
depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly
prohibited.
- The behavior of a C++ program is undefined if it declares:
- an explicit specialization of any member function of a standard library class template, or
- an explicit specialization of any member function template of a standard library class or class template, or
- an explicit or partial specialization of any member class template of a standard library class or class template.
In addition to restricting extensions to the std
namespace, the C++14 Standard goes on in §17.6.4.2.2 to say:
- The behavior of a C++ program is undefined if it adds declarations or definitions to namespace posix or to a namespace within namespace posix
unless otherwise specified. The namespace posix is reserved for use by ISO/IEC 9945 and other POSIX standards.
However, the standard allows specializing standard class templates in namespace std
. In that case, the specialization must respect the
requirement of the original template and has to be for a "program-defined type" (a type that is specific to the program, by opposition to a type from
the standard).
You may therefore think that it’s legitimate to reopen std
to define a version of extension points (std::swap
,
std::hash
…) that work with your types, but it’s not necessary: If you call these extension points according to the correct pattern, the
user-defined version will be found too.
The only extension points for which the specialization is the recommended approach are std::out_ptr
and
std::inout_ptr
.
This rule raises an issue for any modification of the standard std
and posix
namespaces that is not a template
specialization.
Noncompliant code example
namespace MyNamespace {
class MyType {/*...*/};
}
namespace std { // Noncompliant
int x;
void swap(MyNamespace::MyType &m1, MyNamespace::MyType &m2);
}
Compliant solution
namespace expanded_std {
int x;
}
namespace MyNamespace {
class MyType {/*...*/};
void swap(MyType &m1, MyType &m2);
}