This is very pedantic but in C++03 it was apparently non-conforming for a program to overload (not specialize) a template function in the std namespace: see mention of this here and long discussion on comp.lang.c++.moderated
i.e. this was ok:
namespace std
{
template <>
void swap (Foo & f, Foo & g)
{
// ...
}
}
but this was not (if I understand correctly...):
namespace std
{
template <typename T>
void swap (TempateFoo<T> & f, TempateFoo<T> & g)
{
// ...
}
}
Is this still true in C++11? Also, does this apply to template classes (like std::hash) too, or just template functions?
EDIT: also, is there any example of a standard library implementation such that the latter would break things in practice? And if not, is there a specific reason for disallowing overloads like in the second case above? (what could potentially break in theory?)
It is not possible to define a partial specialization of a function template in C++, so your second example defines an overload not a specialization. Since the standard only allows specializations to be added to namespace std, your overload is illegal.
Is this still true in C++11?
Yes.
Also, does this apply to template classes (like std::hash) too, or just template functions?
You can't overload class templates anyway, you can only overload functions. The same rules apply though, you can only specialize a class template if the specialization depends on a user-defined (meaning non-standard) type.
is there a specific reason for disallowing overloads like in the second case above? (what could potentially break in theory?)
As one example, the implementation might want to take the address of a function but if you've overloaded the function then taking the address could cause an ambiguity and fail to compile, meaning you've just broken valid code in the standard library.
n3376 17.6.4.2.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.
17.6.4.2.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.
Related
It is written in many places (for example here), that specialisations of types from namespace std are only allowed if the specialisation "depends on user-defined types". Does this definition in the standard explicitly exclude to specialise std types based on user-defined concepts?
For example, is this allowed?
namespace std {
template<MyConcept T>
struct hash<T> {
size_t hash(T const& v) const { ... }
};
}
This would greatly simplify many specialisations in my code where I have a lot of different but similar classes adhering to the same concept which can be hashed all in the same way.
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.
Example:
namespace X{
inline namespace Y{
template<typename T>
struct A{
};
}
}
namespace X{
template<typename Z>
A(std::vector<Z>) -> A<Z>;
}
This causes a compile error in Clang 11, which says "Deduction guide must be declared in the same scope as template X::Y::A"
Similar to the template specialization, the deduction guide should also be declared within the same semantic scope as the class template. So why can I specialize the class template outside the inline namespace, but for a deduction guide I can't?
Especially, this causes another problem:
template<typename T>
struct Q{
operator std::vector<T>() {
return {};
}
};
namespace std{
template<typename T>
vector(Q<T>) -> vector<T>;
}
The compiler refuses if I want to define a class template with a conversion to std::vector and declare a deduction guide for it. In this case (for libc++), I have to declare it in namespace std::__1.
Is there some solution or explanation in the CPP standard?
so why I can specialize the class template outside the inline namespace, but for deduction guide I can't?
Because you are allowed to specialize the template. From C++ standard [namespace.def]/7:
Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup whenever one of them is, and a using-directive that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace.
Furthermore, each member of the inline namespace can subsequently be partially specialized, explicitly instantiated, or explicitly specialized as though it were a member of the enclosing namespace
For the deduction guide it needs to be in the same scope as the class template. From the standard [temp.deduct.guide]/3:
[...] A deduction-guide shall be declared in the same scope as the corresponding class template and, for a member class template, with the same access. [...]
Solution would be to explicitly give X::Y scope:
namespace X::inline Y{
template<typename Z>
A(std::vector<Z>) -> A<Z>;
}
The intent behind template specialization is that you can add specializations to a template even if you're not the author of the template. One might do this because they are the author of a type which is being used by this specialization. The C++ standard library's rules forbid adding declarations to the std namespace except for template specializations for precisely this reason.
Deduction guides are not like template specializations. They are considered part of the class template's definition, much like constructors and other member functions. As such, they are expected to be written by the creator of the class, typically immediately following the template class's definition. Given these expectations, it doesn't make sense for deduction guides to exist in a scope other than the scope of the template class definition itself.
Basically, you are not meant to be able to add deduction guides to someone else's class templates.
The very first version of the CTAD proposal, as well as every derivative version thereof, focuses on mapping constructor arguments to class template parameters. What will eventually be known as "deduction guides" were first discussed as "Canonical factory functions". But the text around it is particularly telling:
We suggest a notation to allow constructors to specify their template parameters by either explicitly declaring the signatures for any further needed constructor deductions outside the class
Notice how focused the text is on "constructors". These canonical factory functions are maps between constructors and template arguments. They are considered, conceptually at least, to be constructors of a sort. After all, implicit guides are generated from constructors, so it stands to reason that explicit guides are conceptually equivalent to a class constructor.
Indeed, the prototypical example of why you need explicit deduction guides (that is, why you can't rely entirely on implicit guides) is focused on the constructors of the type. Namely, vector's iterator constructor:
template<typename Iter>
vector(Iter first, Iter last);
A deduction guide is needed to access this constructor because Iter doesn't obviously map to the template parameters of vector<T, A>.
The bottom line is this: explicit deduction guides are built around a class's constructors (though those constructors don't have to exist). They exist to map constructor argument types to class template parameters. If you cannot add a constructor to a class from outside of the class's definition, then it stands to reason that you cannot add an explicit deduction guide from outside of the class's definition either.
Obviously explicit guides are written outside of a template class's definition, but the principle is the same: guides are part of a class's interface.
Implicit conversion via operator Typename does not add a constructor to Typename. It may permit Typename(other_type) to work, but as far as the language standard is concerned, this is a copy/move into Typename. It isn't modifying the definition of Typename.
I am studying this fascinating answer to a subtle question regarding the best practice to implement the swap function for user-defined types. (My question was initially motivated by a discussion of the illegality of adding types to namespace std.)
I will not re-print the code snippet from the above-linked answer here.
Instead, I would like to understand the answer.
The answer I've linked above states, beneath the first code snippet, in regards to overloading swap in namespace std (rather than specializing it in that namespace):
If your compiler prints out something different then it is not
correctly implementing "two-phase lookup" for templates.
The answer then goes on to point out that specializing swap in namespace std (as opposed to overloading it) produces a different result (the desired result in the case of specialization).
However, the answer proceeds with an additional case: specializing swap for a user-defined template class - in which case, again, the desired result is not achieved.
Unfortunately, the answer simply states the facts; it does not explain why.
Can someone please elaborate on that answer, and describe the process of lookup in the two specific code snippets provided in that answer:
overloading swap in namespace std for a user-defined non-template class (as in the first code snippet of the linked answer)
specializing swap in namespace std for a user-defined template class (as in the final code snippet of the linked answer)
In both cases, the generic std::swap is called, rather than the user-defined swap. Why?
(This will shed light on the nature of two-phase lookup, and the reason for the best practice for implementing user-defined swap; thanks.)
Preamble with plenty of Standardese
The call to swap() in the example entails a dependent name because its arguments begin[0] and begin[1] depend on the template parameter T of the surrounding algorithm() function template. Two-phase name lookup for such dependent names is defined in the Standard as follows:
14.6.4.2 Candidate functions [temp.dep.candidate]
1 For a function call where the postfix-expression is a dependent name,
the candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:
— For the part of the lookup using unqualified name lookup (3.4.1), only function declarations from the template definition
context are found.
— For the part of the lookup using associated
namespaces (3.4.2), only function declarations found in either the
template definition context or the template instantiation context are
found.
Unqualified lookup is defined by
3.4.1 Unqualified name lookup [basic.lookup.unqual]
1 In all the cases listed in 3.4.1, the scopes are searched for a
declaration in the order listed in each of the respective categories;
name lookup ends as soon as a declaration is found for the name. If no
declaration is found, the program is ill-formed.
and argument-dependent lookup (ADL) as
3.4.2 Argument-dependent name lookup [basic.lookup.argdep]
1 When the postfix-expression in a function call (5.2.2) is an
unqualified-id, other namespaces not considered during the usual
unqualified lookup (3.4.1) may be searched, and in those namespaces,
namespace-scope friend function or function template declarations
(11.3) not otherwise visible may be found. These modifications to the
search depend on the types of the arguments (and for template template
arguments, the namespace of the template argument).
Applying the Standard to the example
The first example calls exp::swap(). This is not a dependent name and does not require two-phase name lookup. Because the call to swap is qualified, ordinary lookup takes place which finds only the generic swap(T&, T&) function template.
The second example (what #HowardHinnant calls "the modern solution") calls swap() and also has an overload swap(A&, A&) in the same namespace as where class A lives (the global namespace in this case). Because the call to swap is unqualified, both ordinary lookup and ADL take place at the point of definition (again only finding the generic swap(T&, T&)) but another ADL takes place at the point of instantiation (i.e where exp::algorithm() is being called in main()) and this picks up swap(A&, A&) which is a better match during overload resolution.
So far so good. Now for the encore: the third example calls swap() and has a specialization template<> swap(A&, A&) inside namespace exp. The lookup is the same as in the second example, but now ADL does not pick up the template specialization because it is not in an associated namespace of class A. However, even though the specialization template<> swap(A&, A&) does not play a role during overload resolution, it is still instantiated at the point of use.
Finally, the fourth example calls swap() and has an overload template<class T> swap(A<T>&, A<T>&) inside namespace exp for template<class T> class A living in the global namespace. The lookup is the same as in the third example, and again ADL does not pick up the overload swap(A<T>&, A<T>&) because it is not in an associated namespace of the class template A<T>. And in this case, there is also no specialization that has to be instantiated at the point of use, so the generic swap(T&, T&) is being callled here.
Conclusion
Even though you are not allowed to add new overloads to namespace std, and only explicit specializations, it would not even work because of the various intricacies of two-phase name lookup.
It is impossible to overload swap in namespace std for a user defined type. Introduction an overload (as opposed to a specialization) in namespace std is undefined behavior (illegal under the standard, no diagnosis required).
It is impossible to specialize a function in general for a template class (as opposed to a template class instance -- ie, std::vector<int> is an instance, while std::vector<T> is the entire template class). What appears to be a specialization is actually an overload. So the first paragraph applies.
The best practice for implementing user-defined swap is to introduce a swap function or overload in the same namespace as your template or class lives in.
Then, if swap is called in the right context (using std::swap; swap(a,b);), which is how it is called in std library, ADL will kick in, and your overload will be found.
The other option is to do a full specialization of swap in std for your particular type. This is impossible (or impractical) for template classes, as you need to specialize for each and every instance of your template class that exists. For other classes, it is fragile, as specialization applies to only that particular type: subclasses will have to be respecialized in std as well.
In general, specialization of functions is extremely fragile, and you are better off introducing overrides. As you cannot introduce overrides into std, the only place they will be reliably found from is in your own namespace. Such overrides in your own namespace are preferred over overrides in std as well.
There are two ways to inject a swap into your namespace. Both work for this purpose:
namespace test {
struct A {};
struct B {};
void swap(A&, A&) { std::cout << "swap(A&,A&)\n"; }
struct C {
friend void swap(C&, C&) { std::cout << "swap(C&, C&)\n"; }
};
void bob() {
using std::swap;
test::A a, b;
swap(a,b);
test::B x, y;
swap(x, y);
C u, v;
swap(u, v);
}
}
void foo() {
using std::swap;
test::A a, b;
swap(a,b);
test::B x, y;
swap(x, y);
test::C u, v;
swap(u, v);
test::bob();
}
int main() {
foo();
return 0;
}
the first is to inject it into the namespace directly, the second is to include it as an inline friend. The inline friend for "external operators" is a common pattern that basically means you can only find swap via ADL, but in this particular context does not add much.
The STL functors are implemented like this:
template<class T>
struct less{
bool operator()(T const& lhs, T const& rhs){
return lhs < rhs;
}
};
This makes us mention the (possibly long) type everytime we create such a functor. Why are they not implemented like shown below? Any reasons?
struct less{
template<class T>
bool operator()(T const& lhs, T const& rhs){
return lhs < rhs;
}
};
That would make them usable without any mentioning of (possibly long) types.
It would also make it impossible to specialize them for user defined types.
They are supposed to be a customization point.
To summarize the discussions in the comments:
Although it is technically possible to do like Xeo suggests, the language standard doesn't allow it.
It is very hard to write a working class template if users are allowed to specialize individual functions of the template. In some cases it might however be a good idea to specialize the whole class for a user defined type.
Therefore the C++98 standard writes (17.4.3.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.
As it isn't "otherwise specified" that Xeo's code is allowed, we are to understand that it is not. Perhaps not totally obvious! Or that "template specializations" only apply to classes.
The new C++11 standard has had this part expanded, and spells it out in more detail (17.6.4.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.
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.
Maybe:
std::multiset<long, std::less<int> > moduloset;
Odd thing to do, but the point is that std::less<int>, std::less<long>, std::less<unsigned int> implement different mathematical functions which produce different results when passed (the result of converting) certain argument expressions. Various algorithms and other standard library components work by specifying a functor, so it makes sense to me that there are different functors to represent those different mathematical functions, not just different overloads of operator() on one functor.
Furthermore, a functor with a template operator() can't be an Adaptable Binary Predicate, since it doesn't have argument types (an argument can have any type). So if std::less were defined as you suggest then it couldn't participate in the stuff in <functional>.
Also on a highly speculative note -- std::less was probably designed before support for template member functions was at all widespread, since there are various notes in the SGI STL documentation that say, "if your implementation doesn't support member templates then this isn't available". For such a simple component there would, I guess, be an incentive to do something that works today. Once it exists, the standardization could then have removed it in favour of something else, but was it worth disrupting existing code? If it was that big a deal, then either you or the standard could introduce a flexible_less functor as you describe.
Finally, why
template<class T>
bool operator()(T const& lhs, T const& rhs){
return lhs < rhs;
}
rather than
template<class T, class U>
bool operator()(T const& lhs, U const& rhs){
return lhs < rhs;
}
For user-defined types, the two might not be the same. Yes, this is an unfair question, since I don't know why there's no two-template-argument version of std::less ;-)
Consider this code:
template <int N>
struct X
{
friend void f(X *) {}
};
int main()
{
f((X<0> *)0); // Error?
}
compilers seem to heavily disagree. (MSVC08/10 says no, GCC<4.5 says yes, but 4.5 says no, sun 5.1 says yes, intel 11.1 says yes too but comeau says no (both are EDG)).
According to "C++ Templates - The complete guide":
... it is assumed that a call
involving a lookup for friends in
associated classes actually causes the
class to be instantiated ... Although
this was clearly intended by those who
wrote the C++ standard, it is not
clearly spelled out in the standard.
I couldn't find the relevant section in the standard. Any reference?
Consider this variation:
template <int N>
struct X
{
template <int M>
friend void f(X<M> *) {}
};
template <>
struct X<0>
{
};
int main()
{
X<1>();
f((X<0> *)0); // Error?
}
The key issue here is wether the viable function injected by X<1> should be visible during ADL for X<0>? Are they associated? All compilers mentioned above accept this code, except for Comeau which only accepts it in relaxed mode. Not sure what the standard has to say about this either.
What's your take on that?
The Standard says at 14.7.1/4
A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type or if the completeness of the class type affects the semantics of the program; in particular, if an expression whose type is a class template specialization is involved in overload resolution, pointer conversion, pointer to member conversion, the class template specialization is implicitly instantiated (3.2);
Note that Vandervoorde made an issue report here, and the committee found
The standard already specifies that this creates a point of instantiation.
For your second case - you need to consider the associated classes and namespaces of the argument f(X<0>*). These are, since this is a pointer to a class template specialization (note that "template-id" below is not quite correct - C++0x corrected that to use the correct term) and also a pointer to a class (this confusing split was also corrected in C++0x - it lists these two cases in one bullet point).
If T is a template-id, its associated namespaces and classes are the namespace in which the template is
defined; [... lots of noise ...]
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces in which its associated classes are defined.
So to summary, we have as associated classes are X<0> and the associated namespaces are the global namespace. Now the friend functions that are visible are
Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup
There is no friend function declared in X<0> so the friend function declaration is not visible when looking into the global namespace. Note that X<0> is an entirely different class-type than X<1>. The implicit instantiation of X<1> you do there has no effect on this call - it just adds a non-visible name into the global namespace that refers to a friend function of class X<1>.