extending namespace std via partial template specialization - c++

As far as I know, we are allowed (with some exceptions that I won't mention here) to "extend" namespace std by totally specializing a std template function such as std::swap, i.e.
namespace std
{
template<>
void swap<Foo>(Foo& lhs, Foo& rhs){...}
}
is perfectly valid.
Since C++11, we can now partially specialize functions. I believe that we can then play the same game and extend std via partial specialization, like
namespace std
{
template<typename T>
void swap<Foo<T>>(Foo<T>& lhs, Foo<T>& rhs){...}
}
however I am not sure about this and couldn't find the proper explaining section in the standard. Is the code immediately above correct or does it lead to UB?
PS: As #Columbo mentioned in the answer, we cannot partially specialize function templates, not even in C++11/14. For some reason I thought one can do that, I believed it was at least a proposal.

You might mean [namespace.std]/1:
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
prohibited181.
181) Any library code that instantiates other library templates must be prepared to work adequately with any user-supplied
specialization that meets the minimum requirements of the Standard.
If partial specializations of function templates are ever introduced, this quote would also implicitly cover them (as it doesn't restrict itself on explicit specialization).

Related

Will specialization of function templates in std for program-defined types no longer be allowed in C++20?

Quote from cppreference.com:
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.
Does it mean, that starting from C++20, adding specializations of function templates to the std namespace for user-defined types will be no longer allowed? If so, it implies that many pieces of existing code can break, doesn't it? (It seems to me to be kind-of a "radical" change.) Moreover, it will inject into such codes undefined behavior, which will not trigger compilations errors (warnings hopefully will).
As it stands now it definitly looks that way. Previously [namespace.std] contained
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.
While the current draft states
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.
emphasis mine
And it looks like the paper Thou Shalt Not Specialize std Function Templates! by Walter E. Brown is responsible for it. In it he details an number of reason why this should be changed such as:
Herb Sutter: “specializations don’t participate in overloading. [...] If you want to customize a function base template and want that
customization to participate in overload resolution (or, to always be
used in the case of exact match), make it a plain old function, not a
specialization. And, if you do provide overloads, avoid also providing
specializations.”
David Abrahams: “it’s wrong to use function template specialization [because] it interacts in bad ways with overloads. [...] For example,
if you specialize the regular std::swap for std::vector<mytype>&,
your specialization won’t get chosen over the standard’s vector
specific swap, because specializations aren’t considered during
overload resolution.”
Howard Hinnant: “this issue has been settled for a long time. . . . Disregard Dave’s expert opinion/answer in this area at your own
peril.”
Eric Niebler: “[because of] the decidedly wonky way C++ resolves function calls in templates. . . , [w]e make an unqualified call to
swap in order to find an overload that might be defined in [...]
associated namespaces[...] , and we do using std::swap so that, on
the off-chance that there is no such overload, we find the default
version defined in the std namespace.”
High Integrity C++ Coding Standard: “Overload resolution does not take into account explicit specializations of function templates. Only
after overload resolution has chosen a function template will any
explicit specializations be considered.”
Not really that radical. This change is based on this paper from Walter E. Brown. The paper goes into rationale rather deeply, but ultimately it boils down to this:
Specialization of function templates is rather poor as a customization point. Overloading and ADL are much better in that regard. There are other customization points discussed in the paper as well.
The standard library doesn't rely on this poor customization point too much already.
The wording change that's put into place actually permits adding entire declarations to namespace std (not just specializations) where it's explicitly permitted. So now there are better customization points.
Given #1 and #2, it's rather unlikely existing code will break. Or at least, not enough for this to be a major problem. Code that used auto and register also "broke" in the past, but that minuscule amount of C++ code didn't stop progress.

Is there a reason why numeric_limits do not work on reference types?

If you mistakenly do something like:
#include<limits>
int arr[3];
auto x = std::numeric_limits<decltype(arr[0])>::max();
You will get unhelpful error message from the file in the STL implementation.
Problem is that template argument is a reference, so the fix is to remove it:
auto x = std::numeric_limits<std::remove_reference_t<decltype(arr[0])>>::max();
Now my question is why numeric_limits do not know to do this by themselves?
I would understand that you do not want to remove pointerness(since max of char pointer and max of char are very very different things), but I would assume that whenever you have a reference as an argument to numeric_limits you would be happy with result that is obtained by removing it.
From a technical point of view, there is no reason why std::numeric_limits<T> couldn't work with references. All what would be needed it to add a partial specialisations like this:
namespace std {
template <typename T> struct numeric_limits<T&>: numeric_limits<T> {};
template <typename T> struct numeric_limits<T&&>: numeric_limits<T> {};
template <typename T> struct numeric_limits<T const>: numeric_limits<T> {};
template <typename T> struct numeric_limits<T volatile>: numeric_limits<T> {};
template <typename T> struct numeric_limits<T const volatile>: numeric_limits<T> {};
}
A user can't add these specialisations, of course. However, that's not a huge constraint as a custom variant of numeric_limits can be created in a suitable namespace.
As it is technically doable the question now becomes why the standard doesn't provide these declarations. I don't think there will be a conclusive answer (unless this idea was discussed and discarded with a suitable and still accessible record). Here are some of the potential answers:
The feature wasn't proposed. When std::numeric_limits was introduced it specifically targeted replacing the macros in <limits.h> with a more a C++ approach. Something like decltype(expr) and forwarding references didn't exist, i.e., template arguments wouldn't be "accidentally" deduced as reference types. Thus, removing qualifiers wasn't a concern at the time.
I'm not sure if at the point in history when numeric_limits were added partial template specialisation already existed. Even if it existed, anything resembling template meta programming didn't exist. As a result, it may not have been possible or assumed to be possible to meddle with the template argument type in the necessary way.
Even if it were considered, I doubt the committee would have gone with adding the partial specialisations: numeric_limits<T> inspects the traits of type T but reference types don't have a max() or digits. Also, if reference types are supported because "clearly" the desired property must be the one of the underlying type where to stop: should std::numeric_limits<int*>::max() provide the same value as std::numeric_limits<int>::max(), too? After all, it also doesn't make any sense on pointers.
Considering that the original proposal almost certainly didn't cover the case of qualified types (see above), another reason why the feature isn't available is that it simply wasn't proposed: without a proposal the standard won't get changed. Whether the standard would get changed if the feature were proposed is a separate question. There is a proposal in this general space (P0437r0) but browsing over it I don't think this proposal covers qualified types, either.

C++ template explicit specialization - calling existing member function

I'm using explicit template specialization to initialize a std::vector with information but only for a specific type of std::vector, thus the explicit specialization. Within the constructor, if I try to call push_back or any other existing function in std::vector, compilation fails. What is the problem and how do I fix it?
simplified example:
namespace std
{
template<>
class vector<int>
{
public:
vector(void)
{
int value = 5;
push_back(value);
}
};
}
compiler message:
In constructor 'std::vector<int>::vector()':
error: 'push_back' was not declared in this scope
push_back(value);
^
Explicit specializations are completely different classes that are separate from the primary template. You have to rewrite everything.
In normal situations where you control the primary template, you would typically have some sort of common base class or base class template to collect common structures.
With a given library, it is generally a very bad idea to add specializations (unless the library explicitly says it's OK). With the C++ standard library, this is outright undefined behaviour.
(The main problem is that other translation units may be using the template instantiation which you're specializing without seeing your specialization, which violates the one-definition rule.)
Template specializations are unrelated types from both the primary template and any other specialization. It is unclear what you are attempting to do, as it is also illegal to provide specializations of templates in the std namespace unless the specialization uses your own user defined type.
If you can explain the problem to solve, you might get other options, like specializing a member function rather than the template itself...

Why does the Standard prohibit friend declarations of partial specializations?

The C++ standard prohibits friend declarations of partial specializations. (§14.5.3/8):
Friend declarations shall not declare partial specializations. [Example:
template<class T> class A { };
class X {
template <class T> friend class A<T*>; //error
};
--end example]
Other questions, e.g. this one,
have received answers that invoke this prohibition, but I would like to know the
rationale. I don't see it and can't find it with my favourite search engine. I
can find however that it goes right back to the C++98 standard, so presumably
the rationale is quite basic and clear. Can someone explain it to me?
I don't have a reference but I suspect that this is because it would result in the partial specialization being declared in the scope of the friend-declaring class rather than the scope of the template in question, and rather than creating a bunch of rules to force the friend declaration to result in the specialization being in the correct scope, they simply prohibit it.
Here is some undirect explanation:
http://www.cprogramming.com/tutorial/template_specialization.html
A final implementation detail comes up with partial specializations:
how does the compiler pick which specialization to use if there are a
combination of completely generic types, some partial specializations,
and maybe even some full specializations? The general rule of thumb is
that the compiler will pick the most specific template
specialization--the most specific template specialization is the one
whose template arguments would be accepted by the other template
declarations, but which would not accept all possible arguments that
other templates with the same name would accept.
I infer that maybe it is not permitted to prevent any ambiguity in the determination of specialization type.

is it ok to specialize std::numeric_limits<T> for user-defined number-like classes?

The documentation of std::numeric_limits<T> says it should not be specialized for non-fundamental types. What about number-like user-defined types? If I define my own type T which represents a numeric value and overloads numeric operators, and for which the information represented by numeric_limits makes sense -- will anything break if I specialize numeric_limits for that type?
Short answer:
Go ahead, nothing bad will happen.
Long answer:
The C++ standard extensively protects the ::std namespace in C++11 17.6.4.2.1, but specifically allows your case in paragraphs 1 and 2:
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.
[...] 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.
The older C++03 has a similar definition in 17.4.3.1/1:
It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces
within namespace std unless otherwise specified. A program may add template specializations for any
standard library template to namespace std. Such a specialization (complete or partial) of a standard
library template results in undefined behavior unless the declaration depends on a user-defined name of
external linkage and unless the specialization meets the standard library requirements for the original template.
After getting past this fundamental stepping stone, you already pointed out, C++03 18.2.1/4 forbids specializations of ::std::numeric_limits for certain types:
Non-fundamental standard types, such as complex (26.2.2), shall not have specializations.
The more current C++11 18.3.2.1/4 has a slightly different wording:
Non-arithmetic standard types, such as complex<T> (26.4.2), shall not have specializations.
Both of these formulations however allow specializations for non-standard types, which T is, since you defined it yourself (as #BoPersson already pointed out in the comments).
Caveats
C++11 18.3.2.3/1 hints that you should (but does not require you to) ensure that your specialization has all members.
Also, you may wish to ensure that C++11 18.3.2.3/2 is not violated by your specialization:
The value of each member of a specialization of numeric_limits on a cv-qualified type cv T shall be equal
to the value of the corresponding member of the specialization on the unqualified type T.
Which essentially means, that if you wish to specialize it for T, you should also do so for T const, T volatile and T const volatile.
Just an example:
namespace std {
template<> class numeric_limits<Temperature> {
public:
static Temperature lowest() {return Temperature(-273.15f);};
// One can implement other methods if needed
};
}