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);
}