Suppose I have a function that has a parameter that is overloaded by many different types. For example:
ostream& operator<<(ostream&, ...);
so if I have a class Foo
class Foo { ... }
I can define an overload
ostream& operator<<(ostream&, const Foo&);
and it works fine.
Now let’s suppose I have a another class:
template<class T>
class vector {...}
And now I want to define an overload of the function that takes any vector<T> where T can be any valid type. Is this possible to do without defining it for all possible input parameters? What signature should I use for such a definition?
template<class T>
ostream& operator<<(ostream&, const vector<T>& v);
?
Background:
In this instance I actually do want to write an overload for std::vector:
ostream& operator<<(ostream&, const std::vector<T>& x);
to write out something like “{2, 4, 8}” or similiar, as my logging system is built on top of ostream and uses operator<< internally to “stringify” types.
I thought I would pose the question in general, but I should add the constraint that I cannot alter the class (std::vector for example) in this case.
The usual solutions both rely on ADL. The first one is writing a function template, which looks just like in your question:
The other way doesn’t require writing a template, but is intrusive because it’s in the class definition:
In both cases, client code looks like this:
You should probably use the first option, the second one is normally picked when implementing an operator for a class (i.e. you’re writing
vectorin the first place). Note that due to the nature of namespaces you can reopennamespace nsto put your operator in here even if you’re not the writer ofns::vector… except if it’s the case that this is aboutnamespace std, since only writing template specializations is allowed in some cases (and to clarify, function templates can’t be partially specialized, and we can’t use a total specialization here). Given that there is such a thing asstd::vector, it may be the case that you’re interested in the next last ditch option.What if you want to add an overload or write a function template accepting a template from
namespace std?This is strictly my opinion, but I think there’s only one sane way to do that: put your functionality in the namespace of your choice (which is obviously not
namespace stdsince, again, it’s not allowed to put it there), and have client-code ask for that.Client code looks like:
If the name of the namespace is well-chosen and restricted to only contain a limited number of things in it, I think such a using directive is a very reasonable choice. Consider a
using namespace literals::chrono;which allows one to write e.g.cond.wait(24_ms);instead ofcond.wait(std::chrono::milliseconds(24));.The big caveat of this technique is that the functionality must be entirely new. This isn’t a way to emulate partial specialization for function template: if there is a generic function template in
namespace stdthen there is a very high risk that it will be either preferred through ADL or that you’ll end up with an overload resolution ambiguity. The example here makes sense because there is no unrestrictedtemplate<typename T> std::ostream& operator<<(std::ostream& os, T const& t);(or a similar member version).