Adding types to the std namespace
No ... part of the point of a namespace is to prevent name collisions on upgrade.
If you add things to the std namespace, then your code might break with the next release of the library if they decide to add something with the same name.
C++ When is it OK to extend the `std` namespace?
The only case where it is OK to add a definition into the std
namespace is specialization of a template that already exists in the namespace and to explicitly instantiate a template. However, only if they depend on a user defined type.
[namespace.std] (standard draft):
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
(2.1) an explicit specialization of any member function of a standard library class template, or
(2.2) an explicit specialization of any member function template of a standard library class or class template, or
(2.3) an explicit or partial specialization of any member class template of a standard library class or class template.
A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template.
As an example of standard templates that are explicitly designed to be extended for user defined types: std::hash
and std::iterator_traits
.
Adding template specialization in std namespace
C++11, [namespace.std]§1:
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace
std
or to a
namespace within namespacestd
unless otherwise specified. A program may add a template specialization
for any standard library template to namespacestd
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 above paragraph explcitily prohibits specialisations which do not depend on a user-defined type.
As to the motivation: you wouldn't be adding a template specialisation, but a separate declaration, which is also prohibited.
What can and can't I specialize in the std namespace?
Quoting loosely from the standard:
numeric_limits
shall not be specialized for non-arithmetic standard types (e.g.complex<T>
)"[S]pecializations of
shared_ptr
shall be CopyConstructible, CopyAssignable, and LessThanComparable [and] convertible tobool
.""Specializations of
weak_ptr
shall be CopyConstructible and CopyAssignable.""[T]emplate specializations [of
std::hash
] shall meet the requirements of class template hash."Anything in
<type_traits>
: "The behavior of a program that adds specializations for any of the class templates defined in this subclause is undefined unless otherwise specified." (only some specializations ofcommon_type
are explicitly allowed)Locales have certain required specializations.
All specializations of
istreambuf_iterator
shall have a trivial copy constructor, a constexpr default constructor, and a trivial destructor."The effect of instantiating the class template
complex
for any type other than float, double, or long double is unspecified." I take it that means that defining such other specializations is pointless."Specializations and instantiations of the
atomic
template shall have a deleted copy constructor, a deleted copy assignment operator, and a constexpr value constructor.""The class templates
unary_function
andbinary_function
are deprecated. A program shall not declare specializations of these templates."
And of course the overarching clause 17.6.4.2.1, sentence 1 (thanks @sehe and @curiousguy):
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.
And sentence 2:
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.
A program may explicitly instantiate a template defined in the standard library only if the declaration
depends on the name of a user-defined type and the instantiation meets the standard library requirements
for the original template.
Why is using namespace std; considered bad practice?
Consider two libraries called Foo and Bar:
using namespace foo;
using namespace bar;
Everything works fine, and you can call Blah()
from Foo and Quux()
from Bar without problems. But one day you upgrade to a new version of Foo 2.0, which now offers a function called Quux()
. Now you've got a conflict: Both Foo 2.0 and Bar import Quux()
into your global namespace. This is going to take some effort to fix, especially if the function parameters happen to match.
If you had used foo::Blah()
and bar::Quux()
, then the introduction of foo::Quux()
would have been a non-event.
C++ adding class to a namespace: why?
You have to understand the basics of what classes and namespaces are.
classes (along with structs, enums, and enum classes) are used to define user defined types in C++.
You create a class to represent a logical entity and encapsulate details, etc.
namespaces are a way to mark territories of code and qualifying unique names for variables.
if you just write a class in a file, it will be written in the "global namespace" and it is not considered good practice because you are "polluting the namespace".
instead, you should use namespaces to limit the scope where your variable names have meaning. this way, you are not exhausting the pool of sensible class and variable names quickly (how many times have you wanted to write a "Utility" class?)
namespace firstNamespace{
int x=2;
}
namespace secondNamespace{
int x=7;
}
int main ()
{
std::cout << firstNamespace::x << '\n';
std::cout << secondNamespace::x << '\n';
return 0;
}
in this case, you can see that we can "reuse" the variable name x in different Contexts by qualifying a namespace. inside the namespace blocks, we could have more declarations and definitions. including functions, classes, structs, etc.
take not that namespaces remain open and you can add to them later.
for example you can have this:
namespace firstNamespace{
int x=2;
}
namespace secondNamespace{
int x=7;
}
namespace firstNamespace{
int y=11;
}
here, we added firstNamespace::y.
More importantly, you can observe that std is a namespace provided by C++ that contains a lot of useful variables, objects like cout which is of type std::ostream, functions and classeslike std::vector, std::ostream, etc.
so to go back to your question, the reason you want to wrap your class definitions in namespaces is to not pollute the global namespace.
Specializing types from namespace std based on user-defined concepts
The general rule we have, in [namespace.std]/2 is:
Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace std provided that (a) the added declaration depends on at least one program-defined type and (b) the specialization meets the standard library requirements for the original template.
For this specialization:
template<MyConcept T>
struct hash<T> { /* ... */ };
If it is the case that (a) for all T
that satisfy MyConcept
, T
depends on at least one program-defined type and (b) this specialization meets the requirements for hash (i.e. it's invocable, swappable, satisfies the normal hash requirements, etc.), then this is fine.
By depends on at least one program-defined type, it's not just that it's like my::Type
, but it could also include std::vector<my::Type>
and std::tuple<int, char, my::Type*>
, etc. As long as something in there somewhere is program-defined.
Related Topics
Openmp Set_Num_Threads() Is Not Working
Where Are C/C++ Main Function's Parameters
What Is Dynamic Initialization of Object in C++
Reinterpret_Cast VS. C-Style Cast
Why Don't the Std::Fstream Classes Take a Std::String
Inheritance or Composition: Rely on "Is-A" and "Has-A"
How to Read Directly from Physical Memory on Windows
C/C++ Changing the Value of a Const
Error: Variable "Cannot Be Implicitly Captured Because No Default Capture Mode Has Been Specified"
Why Do I Need Double Layer of Indirection for MACros
Partial Class Template Argument Deduction in C++17
Why Doesn't Left Bit Shift << Shift Beyond 31 for Long Int Datatype
2D-Array as Argument to Function
How Does Virtual Method Invocation Work in C++
Hash an Arbitrary Precision Value (Boost::Multiprecision::Cpp_Int)