Adding Types to the Std Namespace

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):

  1. 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.

  2. 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 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 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 to bool."

  • "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 of common_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 and binary_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



Leave a reply



Submit